]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
MFV r322235: 8067 zdb should be able to dump literal embedded block pointer
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / llvm-pdbutil / MinimalTypeDumper.cpp
1 //===- MinimalTypeDumper.cpp ---------------------------------- *- C++ --*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "MinimalTypeDumper.h"
11
12 #include "FormatUtil.h"
13 #include "LinePrinter.h"
14
15 #include "llvm/DebugInfo/CodeView/CVRecord.h"
16 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
17 #include "llvm/DebugInfo/CodeView/CodeView.h"
18 #include "llvm/DebugInfo/CodeView/Formatters.h"
19 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
20 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
21 #include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
22 #include "llvm/Support/FormatVariadic.h"
23 #include "llvm/Support/MathExtras.h"
24
25 using namespace llvm;
26 using namespace llvm::codeview;
27 using namespace llvm::pdb;
28
29 static StringRef getLeafTypeName(TypeLeafKind K) {
30   switch (K) {
31 #define TYPE_RECORD(EnumName, value, name)                                     \
32   case EnumName:                                                               \
33     return #EnumName;
34 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
35   default:
36     llvm_unreachable("Unknown type leaf kind!");
37   }
38   return "";
39 }
40
41 static std::string formatClassOptions(uint32_t IndentLevel,
42                                       ClassOptions Options) {
43   std::vector<std::string> Opts;
44   PUSH_FLAG(ClassOptions, HasConstructorOrDestructor, Options,
45             "has ctor / dtor");
46   PUSH_FLAG(ClassOptions, ContainsNestedClass, Options,
47             "contains nested class");
48   PUSH_FLAG(ClassOptions, HasConversionOperator, Options,
49             "conversion operator");
50   PUSH_FLAG(ClassOptions, ForwardReference, Options, "forward ref");
51   PUSH_FLAG(ClassOptions, HasUniqueName, Options, "has unique name");
52   PUSH_FLAG(ClassOptions, Intrinsic, Options, "intrin");
53   PUSH_FLAG(ClassOptions, Nested, Options, "is nested");
54   PUSH_FLAG(ClassOptions, HasOverloadedOperator, Options,
55             "overloaded operator");
56   PUSH_FLAG(ClassOptions, HasOverloadedAssignmentOperator, Options,
57             "overloaded operator=");
58   PUSH_FLAG(ClassOptions, Packed, Options, "packed");
59   PUSH_FLAG(ClassOptions, Scoped, Options, "scoped");
60   PUSH_FLAG(ClassOptions, Sealed, Options, "sealed");
61
62   return typesetItemList(Opts, 4, IndentLevel, " | ");
63 }
64
65 static std::string pointerOptions(PointerOptions Options) {
66   std::vector<std::string> Opts;
67   PUSH_FLAG(PointerOptions, Flat32, Options, "flat32");
68   PUSH_FLAG(PointerOptions, Volatile, Options, "volatile");
69   PUSH_FLAG(PointerOptions, Const, Options, "const");
70   PUSH_FLAG(PointerOptions, Unaligned, Options, "unaligned");
71   PUSH_FLAG(PointerOptions, Restrict, Options, "restrict");
72   PUSH_FLAG(PointerOptions, WinRTSmartPointer, Options, "winrt");
73   if (Opts.empty())
74     return "None";
75   return join(Opts, " | ");
76 }
77
78 static std::string modifierOptions(ModifierOptions Options) {
79   std::vector<std::string> Opts;
80   PUSH_FLAG(ModifierOptions, Const, Options, "const");
81   PUSH_FLAG(ModifierOptions, Volatile, Options, "volatile");
82   PUSH_FLAG(ModifierOptions, Unaligned, Options, "unaligned");
83   if (Opts.empty())
84     return "None";
85   return join(Opts, " | ");
86 }
87
88 static std::string formatCallingConvention(CallingConvention Convention) {
89   switch (Convention) {
90     RETURN_CASE(CallingConvention, AlphaCall, "alphacall");
91     RETURN_CASE(CallingConvention, AM33Call, "am33call");
92     RETURN_CASE(CallingConvention, ArmCall, "armcall");
93     RETURN_CASE(CallingConvention, ClrCall, "clrcall");
94     RETURN_CASE(CallingConvention, FarC, "far cdecl");
95     RETURN_CASE(CallingConvention, FarFast, "far fastcall");
96     RETURN_CASE(CallingConvention, FarPascal, "far pascal");
97     RETURN_CASE(CallingConvention, FarStdCall, "far stdcall");
98     RETURN_CASE(CallingConvention, FarSysCall, "far syscall");
99     RETURN_CASE(CallingConvention, Generic, "generic");
100     RETURN_CASE(CallingConvention, Inline, "inline");
101     RETURN_CASE(CallingConvention, M32RCall, "m32rcall");
102     RETURN_CASE(CallingConvention, MipsCall, "mipscall");
103     RETURN_CASE(CallingConvention, NearC, "cdecl");
104     RETURN_CASE(CallingConvention, NearFast, "fastcall");
105     RETURN_CASE(CallingConvention, NearPascal, "pascal");
106     RETURN_CASE(CallingConvention, NearStdCall, "stdcall");
107     RETURN_CASE(CallingConvention, NearSysCall, "near syscall");
108     RETURN_CASE(CallingConvention, NearVector, "vectorcall");
109     RETURN_CASE(CallingConvention, PpcCall, "ppccall");
110     RETURN_CASE(CallingConvention, SHCall, "shcall");
111     RETURN_CASE(CallingConvention, SH5Call, "sh5call");
112     RETURN_CASE(CallingConvention, ThisCall, "thiscall");
113     RETURN_CASE(CallingConvention, TriCall, "tricall");
114   }
115   return formatUnknownEnum(Convention);
116 }
117
118 static std::string formatPointerMode(PointerMode Mode) {
119   switch (Mode) {
120     RETURN_CASE(PointerMode, LValueReference, "ref");
121     RETURN_CASE(PointerMode, Pointer, "pointer");
122     RETURN_CASE(PointerMode, PointerToDataMember, "data member pointer");
123     RETURN_CASE(PointerMode, PointerToMemberFunction, "member fn pointer");
124     RETURN_CASE(PointerMode, RValueReference, "rvalue ref");
125   }
126   return formatUnknownEnum(Mode);
127 }
128
129 static std::string memberAccess(MemberAccess Access) {
130   switch (Access) {
131     RETURN_CASE(MemberAccess, None, "");
132     RETURN_CASE(MemberAccess, Private, "private");
133     RETURN_CASE(MemberAccess, Protected, "protected");
134     RETURN_CASE(MemberAccess, Public, "public");
135   }
136   return formatUnknownEnum(Access);
137 }
138
139 static std::string methodKind(MethodKind Kind) {
140   switch (Kind) {
141     RETURN_CASE(MethodKind, Vanilla, "");
142     RETURN_CASE(MethodKind, Virtual, "virtual");
143     RETURN_CASE(MethodKind, Static, "static");
144     RETURN_CASE(MethodKind, Friend, "friend");
145     RETURN_CASE(MethodKind, IntroducingVirtual, "intro virtual");
146     RETURN_CASE(MethodKind, PureVirtual, "pure virtual");
147     RETURN_CASE(MethodKind, PureIntroducingVirtual, "pure intro virtual");
148   }
149   return formatUnknownEnum(Kind);
150 }
151
152 static std::string pointerKind(PointerKind Kind) {
153   switch (Kind) {
154     RETURN_CASE(PointerKind, Near16, "ptr16");
155     RETURN_CASE(PointerKind, Far16, "far ptr16");
156     RETURN_CASE(PointerKind, Huge16, "huge ptr16");
157     RETURN_CASE(PointerKind, BasedOnSegment, "segment based");
158     RETURN_CASE(PointerKind, BasedOnValue, "value based");
159     RETURN_CASE(PointerKind, BasedOnSegmentValue, "segment value based");
160     RETURN_CASE(PointerKind, BasedOnAddress, "address based");
161     RETURN_CASE(PointerKind, BasedOnSegmentAddress, "segment address based");
162     RETURN_CASE(PointerKind, BasedOnType, "type based");
163     RETURN_CASE(PointerKind, BasedOnSelf, "self based");
164     RETURN_CASE(PointerKind, Near32, "ptr32");
165     RETURN_CASE(PointerKind, Far32, "far ptr32");
166     RETURN_CASE(PointerKind, Near64, "ptr64");
167   }
168   return formatUnknownEnum(Kind);
169 }
170
171 static std::string memberAttributes(const MemberAttributes &Attrs) {
172   std::vector<std::string> Opts;
173   std::string Access = memberAccess(Attrs.getAccess());
174   std::string Kind = methodKind(Attrs.getMethodKind());
175   if (!Access.empty())
176     Opts.push_back(Access);
177   if (!Kind.empty())
178     Opts.push_back(Kind);
179   MethodOptions Flags = Attrs.getFlags();
180   PUSH_FLAG(MethodOptions, Pseudo, Flags, "pseudo");
181   PUSH_FLAG(MethodOptions, NoInherit, Flags, "noinherit");
182   PUSH_FLAG(MethodOptions, NoConstruct, Flags, "noconstruct");
183   PUSH_FLAG(MethodOptions, CompilerGenerated, Flags, "compiler-generated");
184   PUSH_FLAG(MethodOptions, Sealed, Flags, "sealed");
185   return join(Opts, " ");
186 }
187
188 static std::string formatPointerAttrs(const PointerRecord &Record) {
189   PointerMode Mode = Record.getMode();
190   PointerOptions Opts = Record.getOptions();
191   PointerKind Kind = Record.getPointerKind();
192   return formatv("mode = {0}, opts = {1}, kind = {2}", formatPointerMode(Mode),
193                  pointerOptions(Opts), pointerKind(Kind));
194 }
195
196 static std::string formatFunctionOptions(FunctionOptions Options) {
197   std::vector<std::string> Opts;
198
199   PUSH_FLAG(FunctionOptions, CxxReturnUdt, Options, "returns cxx udt");
200   PUSH_FLAG(FunctionOptions, ConstructorWithVirtualBases, Options,
201             "constructor with virtual bases");
202   PUSH_FLAG(FunctionOptions, Constructor, Options, "constructor");
203   if (Opts.empty())
204     return "None";
205   return join(Opts, " | ");
206 }
207
208 Error MinimalTypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
209   // formatLine puts the newline at the beginning, so we use formatLine here
210   // to start a new line, and then individual visit methods use format to
211   // append to the existing line.
212   if (!Hashes) {
213     P.formatLine("{0} | {1} [size = {2}]",
214                  fmt_align(Index, AlignStyle::Right, Width),
215                  getLeafTypeName(Record.Type), Record.length());
216   } else {
217     std::string H;
218     if (Index.toArrayIndex() >= HashValues.size()) {
219       H = "(not present)";
220     } else {
221       uint32_t Hash = HashValues[Index.toArrayIndex()];
222       Expected<uint32_t> MaybeHash = hashTypeRecord(Record);
223       if (!MaybeHash)
224         return MaybeHash.takeError();
225       uint32_t OurHash = *MaybeHash;
226       OurHash %= NumHashBuckets;
227       if (Hash == OurHash)
228         H = "0x" + utohexstr(Hash);
229       else
230         H = "0x" + utohexstr(Hash) + ", our hash = 0x" + utohexstr(OurHash);
231     }
232     P.formatLine("{0} | {1} [size = {2}, hash = {3}]",
233                  fmt_align(Index, AlignStyle::Right, Width),
234                  getLeafTypeName(Record.Type), Record.length(), H);
235   }
236   P.Indent(Width + 3);
237   return Error::success();
238 }
239 Error MinimalTypeDumpVisitor::visitTypeEnd(CVType &Record) {
240   P.Unindent(Width + 3);
241   if (RecordBytes) {
242     AutoIndent Indent(P, 9);
243     P.formatBinary("Bytes", Record.RecordData, 0);
244   }
245   return Error::success();
246 }
247
248 Error MinimalTypeDumpVisitor::visitMemberBegin(CVMemberRecord &Record) {
249   P.formatLine("- {0}", getLeafTypeName(Record.Kind));
250   return Error::success();
251 }
252
253 Error MinimalTypeDumpVisitor::visitMemberEnd(CVMemberRecord &Record) {
254   if (RecordBytes) {
255     AutoIndent Indent(P, 2);
256     P.formatBinary("Bytes", Record.Data, 0);
257   }
258   return Error::success();
259 }
260
261 StringRef MinimalTypeDumpVisitor::getTypeName(TypeIndex TI) const {
262   if (TI.isNoneType())
263     return "";
264   return Types.getTypeName(TI);
265 }
266
267 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
268                                                FieldListRecord &FieldList) {
269   if (auto EC = codeview::visitMemberRecordStream(FieldList.Data, *this))
270     return EC;
271
272   return Error::success();
273 }
274
275 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
276                                                StringIdRecord &String) {
277   P.format(" ID: {0}, String: {1}", String.getId(), String.getString());
278   return Error::success();
279 }
280
281 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
282                                                ArgListRecord &Args) {
283   auto Indices = Args.getIndices();
284   if (Indices.empty())
285     return Error::success();
286
287   auto Max = std::max_element(Indices.begin(), Indices.end());
288   uint32_t W = NumDigits(Max->getIndex()) + 2;
289
290   for (auto I : Indices)
291     P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
292                  getTypeName(I));
293   return Error::success();
294 }
295
296 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
297                                                StringListRecord &Strings) {
298   auto Indices = Strings.getIndices();
299   if (Indices.empty())
300     return Error::success();
301
302   auto Max = std::max_element(Indices.begin(), Indices.end());
303   uint32_t W = NumDigits(Max->getIndex()) + 2;
304
305   for (auto I : Indices)
306     P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
307                  getTypeName(I));
308   return Error::success();
309 }
310
311 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
312                                                ClassRecord &Class) {
313   P.format(" `{0}`", Class.Name);
314   if (Class.hasUniqueName())
315     P.formatLine("unique name: `{0}`", Class.UniqueName);
316   P.formatLine("vtable: {0}, base list: {1}, field list: {2}",
317                Class.VTableShape, Class.DerivationList, Class.FieldList);
318   P.formatLine("options: {0}",
319                formatClassOptions(P.getIndentLevel(), Class.Options));
320   return Error::success();
321 }
322
323 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
324                                                UnionRecord &Union) {
325   P.format(" `{0}`", Union.Name);
326   if (Union.hasUniqueName())
327     P.formatLine("unique name: `{0}`", Union.UniqueName);
328   P.formatLine("field list: {0}", Union.FieldList);
329   P.formatLine("options: {0}",
330                formatClassOptions(P.getIndentLevel(), Union.Options));
331   return Error::success();
332 }
333
334 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
335   P.format(" `{0}`", Enum.Name);
336   if (Enum.hasUniqueName())
337     P.formatLine("unique name: `{0}`", Enum.UniqueName);
338   P.formatLine("field list: {0}, underlying type: {1}", Enum.FieldList,
339                Enum.UnderlyingType);
340   P.formatLine("options: {0}",
341                formatClassOptions(P.getIndentLevel(), Enum.Options));
342   return Error::success();
343 }
344
345 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
346   if (AT.Name.empty()) {
347     P.formatLine("size: {0}, index type: {1}, element type: {2}", AT.Size,
348                  AT.IndexType, AT.ElementType);
349   } else {
350     P.formatLine("name: {0}, size: {1}, index type: {2}, element type: {3}",
351                  AT.Name, AT.Size, AT.IndexType, AT.ElementType);
352   }
353   return Error::success();
354 }
355
356 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
357                                                VFTableRecord &VFT) {
358   P.formatLine("offset: {0}, complete class: {1}, overridden vftable: {2}",
359                VFT.VFPtrOffset, VFT.CompleteClass, VFT.OverriddenVFTable);
360   P.formatLine("method names: ");
361   if (!VFT.MethodNames.empty()) {
362     std::string Sep =
363         formatv("\n{0}",
364                 fmt_repeat(' ', P.getIndentLevel() + strlen("method names: ")))
365             .str();
366     P.print(join(VFT.MethodNames, Sep));
367   }
368   return Error::success();
369 }
370
371 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
372                                                MemberFuncIdRecord &Id) {
373   P.formatLine("name = {0}, type = {1}, class type = {2}", Id.Name,
374                Id.FunctionType, Id.ClassType);
375   return Error::success();
376 }
377
378 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
379                                                ProcedureRecord &Proc) {
380   P.formatLine("return type = {0}, # args = {1}, param list = {2}",
381                Proc.ReturnType, Proc.ParameterCount, Proc.ArgumentList);
382   P.formatLine("calling conv = {0}, options = {1}",
383                formatCallingConvention(Proc.CallConv),
384                formatFunctionOptions(Proc.Options));
385   return Error::success();
386 }
387
388 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
389                                                MemberFunctionRecord &MF) {
390   P.formatLine("return type = {0}, # args = {1}, param list = {2}",
391                MF.ReturnType, MF.ParameterCount, MF.ArgumentList);
392   P.formatLine("class type = {0}, this type = {1}, this adjust = {2}",
393                MF.ClassType, MF.ThisType, MF.ThisPointerAdjustment);
394   P.formatLine("calling conv = {0}, options = {1}",
395                formatCallingConvention(MF.CallConv),
396                formatFunctionOptions(MF.Options));
397   return Error::success();
398 }
399
400 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
401                                                FuncIdRecord &Func) {
402   P.formatLine("name = {0}, type = {1}, parent scope = {2}", Func.Name,
403                Func.FunctionType, Func.ParentScope);
404   return Error::success();
405 }
406
407 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
408                                                TypeServer2Record &TS) {
409   P.formatLine("name = {0}, age = {1}, guid = {2}", TS.Name, TS.Age, TS.Guid);
410   return Error::success();
411 }
412
413 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
414                                                PointerRecord &Ptr) {
415   P.formatLine("referent = {0}, {1}", Ptr.ReferentType,
416                formatPointerAttrs(Ptr));
417   return Error::success();
418 }
419
420 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
421                                                ModifierRecord &Mod) {
422   P.formatLine("referent = {0}, modifiers = {1}", Mod.ModifiedType,
423                modifierOptions(Mod.Modifiers));
424   return Error::success();
425 }
426
427 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
428                                                VFTableShapeRecord &Shape) {
429   return Error::success();
430 }
431
432 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
433                                                UdtModSourceLineRecord &U) {
434   P.formatLine("udt = {0}, mod = {1}, file = {2}, line = {3}", U.UDT, U.Module,
435                U.SourceFile.getIndex(), U.LineNumber);
436   return Error::success();
437 }
438
439 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
440                                                UdtSourceLineRecord &U) {
441   P.formatLine("udt = {0}, file = {1}, line = {2}", U.UDT,
442                U.SourceFile.getIndex(), U.LineNumber);
443   return Error::success();
444 }
445
446 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
447                                                BitFieldRecord &BF) {
448   P.formatLine("type = {0}, bit offset = {1}, # bits = {2}", BF.Type,
449                BF.BitOffset, BF.BitSize);
450   return Error::success();
451 }
452
453 Error MinimalTypeDumpVisitor::visitKnownRecord(
454     CVType &CVR, MethodOverloadListRecord &Overloads) {
455   for (auto &M : Overloads.Methods)
456     P.formatLine("- Method [type = {0}, vftable offset = {1}, attrs = {2}]",
457                  M.Type, M.VFTableOffset, memberAttributes(M.Attrs));
458   return Error::success();
459 }
460
461 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
462                                                BuildInfoRecord &BI) {
463   auto Indices = BI.ArgIndices;
464   if (Indices.empty())
465     return Error::success();
466
467   auto Max = std::max_element(Indices.begin(), Indices.end());
468   uint32_t W = NumDigits(Max->getIndex()) + 2;
469
470   for (auto I : Indices)
471     P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
472                  getTypeName(I));
473   return Error::success();
474 }
475
476 Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, LabelRecord &R) {
477   std::string Type = (R.Mode == LabelType::Far) ? "far" : "near";
478   P.format(" type = {0}", Type);
479   return Error::success();
480 }
481
482 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
483                                                NestedTypeRecord &Nested) {
484   P.format(" [name = `{0}`, parent = {1}]", Nested.Name, Nested.Type);
485   return Error::success();
486 }
487
488 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
489                                                OneMethodRecord &Method) {
490   P.format(" [name = `{0}`]", Method.Name);
491   AutoIndent Indent(P);
492   P.formatLine("type = {0}, vftable offset = {1}, attrs = {2}", Method.Type,
493                Method.VFTableOffset, memberAttributes(Method.Attrs));
494   return Error::success();
495 }
496
497 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
498                                                OverloadedMethodRecord &Method) {
499   P.format(" [name = `{0}`, # overloads = {1}, overload list = {2}]",
500            Method.Name, Method.NumOverloads, Method.MethodList);
501   return Error::success();
502 }
503
504 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
505                                                DataMemberRecord &Field) {
506   P.format(" [name = `{0}`, Type = {1}, offset = {2}, attrs = {3}]", Field.Name,
507            Field.Type, Field.FieldOffset, memberAttributes(Field.Attrs));
508   return Error::success();
509 }
510
511 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
512                                                StaticDataMemberRecord &Field) {
513   P.format(" [name = `{0}`, type = {1}, attrs = {2}]", Field.Name, Field.Type,
514            memberAttributes(Field.Attrs));
515   return Error::success();
516 }
517
518 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
519                                                EnumeratorRecord &Enum) {
520   P.format(" [{0} = {1}]", Enum.Name,
521            Enum.Value.toString(10, Enum.Value.isSigned()));
522   return Error::success();
523 }
524
525 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
526                                                BaseClassRecord &Base) {
527   AutoIndent Indent(P);
528   P.formatLine("type = {0}, offset = {1}, attrs = {2}", Base.Type, Base.Offset,
529                memberAttributes(Base.Attrs));
530   return Error::success();
531 }
532
533 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
534                                                VirtualBaseClassRecord &Base) {
535   AutoIndent Indent(P);
536   P.formatLine(
537       "base = {0}, vbptr = {1}, vbptr offset = {2}, vtable index = {3}",
538       Base.BaseType, Base.VBPtrType, Base.VBPtrOffset, Base.VTableIndex);
539   P.formatLine("attrs = {0}", memberAttributes(Base.Attrs));
540   return Error::success();
541 }
542
543 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
544                                                ListContinuationRecord &Cont) {
545   P.format(" continuation = {0}", Cont.ContinuationIndex);
546   return Error::success();
547 }
548
549 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
550                                                VFPtrRecord &VFP) {
551   P.format(" type = {0}", VFP.Type);
552   return Error::success();
553 }