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