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/ArrayRef.h"
12#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
13#include "llvm/DebugInfo/CodeView/EnumTables.h"
14#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
15#include "llvm/DebugInfo/CodeView/TypeCollection.h"
16#include "llvm/DebugInfo/CodeView/TypeIndex.h"
17#include "llvm/DebugInfo/CodeView/TypeRecord.h"
18#include "llvm/Support/FormatVariadic.h"
19#include "llvm/Support/ScopedPrinter.h"
20#include "llvm/Support/raw_ostream.h"
21
22using namespace llvm;
23using namespace llvm::codeview;
24
25static StringRef getLeafTypeName(TypeLeafKind LT) {
26 switch (LT) {
27#define TYPE_RECORD(ename, value, name) \
28 case ename: \
29 return #name;
30#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
31 default:
32 break;
33 }
34 return "UnknownLeaf";
35}
36
37void TypeDumpVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI) const {
38 codeview::printTypeIndex(Printer&: *W, FieldName, TI, Types&: TpiTypes);
39}
40
41void TypeDumpVisitor::printItemIndex(StringRef FieldName, TypeIndex TI) const {
42 codeview::printTypeIndex(Printer&: *W, FieldName, TI, Types&: getSourceTypes());
43}
44
45Error TypeDumpVisitor::visitTypeBegin(CVType &Record) {
46 return visitTypeBegin(Record, Index: TypeIndex::fromArrayIndex(Index: TpiTypes.size()));
47}
48
49Error TypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
50 W->startLine() << getLeafTypeName(LT: Record.kind());
51 W->getOStream() << " (" << HexNumber(Index.getIndex()) << ")";
52 W->getOStream() << " {\n";
53 W->indent();
54 W->printEnum(Label: "TypeLeafKind", Value: unsigned(Record.kind()), EnumValues: getTypeLeafNames());
55 return Error::success();
56}
57
58Error TypeDumpVisitor::visitTypeEnd(CVType &Record) {
59 if (PrintRecordBytes)
60 W->printBinaryBlock(Label: "LeafData", Value: getBytesAsCharacters(LeafData: Record.content()));
61
62 W->unindent();
63 W->startLine() << "}\n";
64 return Error::success();
65}
66
67Error TypeDumpVisitor::visitMemberBegin(CVMemberRecord &Record) {
68 W->startLine() << getLeafTypeName(LT: Record.Kind);
69 W->getOStream() << " {\n";
70 W->indent();
71 W->printEnum(Label: "TypeLeafKind", Value: unsigned(Record.Kind), EnumValues: getTypeLeafNames());
72 return Error::success();
73}
74
75Error TypeDumpVisitor::visitMemberEnd(CVMemberRecord &Record) {
76 if (PrintRecordBytes)
77 W->printBinaryBlock(Label: "LeafData", Value: getBytesAsCharacters(LeafData: Record.Data));
78
79 W->unindent();
80 W->startLine() << "}\n";
81 return Error::success();
82}
83
84Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
85 FieldListRecord &FieldList) {
86 if (auto EC = codeview::visitMemberRecordStream(FieldList: FieldList.Data, Callbacks&: *this))
87 return EC;
88
89 return Error::success();
90}
91
92Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringIdRecord &String) {
93 printItemIndex(FieldName: "Id", TI: String.getId());
94 W->printString(Label: "StringData", Value: String.getString());
95 return Error::success();
96}
97
98Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ArgListRecord &Args) {
99 auto Indices = Args.getIndices();
100 uint32_t Size = Indices.size();
101 W->printNumber(Label: "NumArgs", Value: Size);
102 ListScope Arguments(*W, "Arguments");
103 for (uint32_t I = 0; I < Size; ++I) {
104 printTypeIndex(FieldName: "ArgType", TI: Indices[I]);
105 }
106 return Error::success();
107}
108
109Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringListRecord &Strs) {
110 auto Indices = Strs.getIndices();
111 uint32_t Size = Indices.size();
112 W->printNumber(Label: "NumStrings", Value: Size);
113 ListScope Arguments(*W, "Strings");
114 for (uint32_t I = 0; I < Size; ++I) {
115 printItemIndex(FieldName: "String", TI: Indices[I]);
116 }
117 return Error::success();
118}
119
120Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ClassRecord &Class) {
121 uint16_t Props = static_cast<uint16_t>(Class.getOptions());
122 W->printNumber(Label: "MemberCount", Value: Class.getMemberCount());
123 W->printFlags(Label: "Properties", Value: Props, Flags: getClassOptionNames());
124 printTypeIndex(FieldName: "FieldList", TI: Class.getFieldList());
125 printTypeIndex(FieldName: "DerivedFrom", TI: Class.getDerivationList());
126 printTypeIndex(FieldName: "VShape", TI: Class.getVTableShape());
127 W->printNumber(Label: "SizeOf", Value: Class.getSize());
128 W->printString(Label: "Name", Value: Class.getName());
129 if (Props & uint16_t(ClassOptions::HasUniqueName))
130 W->printString(Label: "LinkageName", Value: Class.getUniqueName());
131 return Error::success();
132}
133
134Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, UnionRecord &Union) {
135 uint16_t Props = static_cast<uint16_t>(Union.getOptions());
136 W->printNumber(Label: "MemberCount", Value: Union.getMemberCount());
137 W->printFlags(Label: "Properties", Value: Props, Flags: getClassOptionNames());
138 printTypeIndex(FieldName: "FieldList", TI: Union.getFieldList());
139 W->printNumber(Label: "SizeOf", Value: Union.getSize());
140 W->printString(Label: "Name", Value: Union.getName());
141 if (Props & uint16_t(ClassOptions::HasUniqueName))
142 W->printString(Label: "LinkageName", Value: Union.getUniqueName());
143 return Error::success();
144}
145
146Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
147 uint16_t Props = static_cast<uint16_t>(Enum.getOptions());
148 W->printNumber(Label: "NumEnumerators", Value: Enum.getMemberCount());
149 W->printFlags(Label: "Properties", Value: uint16_t(Enum.getOptions()),
150 Flags: getClassOptionNames());
151 printTypeIndex(FieldName: "UnderlyingType", TI: Enum.getUnderlyingType());
152 printTypeIndex(FieldName: "FieldListType", TI: Enum.getFieldList());
153 W->printString(Label: "Name", Value: Enum.getName());
154 if (Props & uint16_t(ClassOptions::HasUniqueName))
155 W->printString(Label: "LinkageName", Value: Enum.getUniqueName());
156 return Error::success();
157}
158
159Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
160 printTypeIndex(FieldName: "ElementType", TI: AT.getElementType());
161 printTypeIndex(FieldName: "IndexType", TI: AT.getIndexType());
162 W->printNumber(Label: "SizeOf", Value: AT.getSize());
163 W->printString(Label: "Name", Value: AT.getName());
164 return Error::success();
165}
166
167Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) {
168 printTypeIndex(FieldName: "CompleteClass", TI: VFT.getCompleteClass());
169 printTypeIndex(FieldName: "OverriddenVFTable", TI: VFT.getOverriddenVTable());
170 W->printHex(Label: "VFPtrOffset", Value: VFT.getVFPtrOffset());
171 W->printString(Label: "VFTableName", Value: VFT.getName());
172 for (auto N : VFT.getMethodNames())
173 W->printString(Label: "MethodName", Value: N);
174 return Error::success();
175}
176
177Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) {
178 printTypeIndex(FieldName: "ClassType", TI: Id.getClassType());
179 printTypeIndex(FieldName: "FunctionType", TI: Id.getFunctionType());
180 W->printString(Label: "Name", Value: Id.getName());
181 return Error::success();
182}
183
184Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) {
185 printTypeIndex(FieldName: "ReturnType", TI: Proc.getReturnType());
186 W->printEnum(Label: "CallingConvention", Value: uint8_t(Proc.getCallConv()),
187 EnumValues: getCallingConventions());
188 W->printFlags(Label: "FunctionOptions", Value: uint8_t(Proc.getOptions()),
189 Flags: getFunctionOptionEnum());
190 W->printNumber(Label: "NumParameters", Value: Proc.getParameterCount());
191 printTypeIndex(FieldName: "ArgListType", TI: Proc.getArgumentList());
192 return Error::success();
193}
194
195Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, MemberFunctionRecord &MF) {
196 printTypeIndex(FieldName: "ReturnType", TI: MF.getReturnType());
197 printTypeIndex(FieldName: "ClassType", TI: MF.getClassType());
198 printTypeIndex(FieldName: "ThisType", TI: MF.getThisType());
199 W->printEnum(Label: "CallingConvention", Value: uint8_t(MF.getCallConv()),
200 EnumValues: getCallingConventions());
201 W->printFlags(Label: "FunctionOptions", Value: uint8_t(MF.getOptions()),
202 Flags: getFunctionOptionEnum());
203 W->printNumber(Label: "NumParameters", Value: MF.getParameterCount());
204 printTypeIndex(FieldName: "ArgListType", TI: MF.getArgumentList());
205 W->printNumber(Label: "ThisAdjustment", Value: MF.getThisPointerAdjustment());
206 return Error::success();
207}
208
209Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
210 MethodOverloadListRecord &MethodList) {
211 for (const auto &M : MethodList.getMethods()) {
212 ListScope S(*W, "Method");
213 printMemberAttributes(Access: M.getAccess(), Kind: M.getMethodKind(), Options: M.getOptions());
214 printTypeIndex(FieldName: "Type", TI: M.getType());
215 if (M.isIntroducingVirtual())
216 W->printHex(Label: "VFTableOffset", Value: M.getVFTableOffset());
217 }
218 return Error::success();
219}
220
221Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) {
222 printItemIndex(FieldName: "ParentScope", TI: Func.getParentScope());
223 printTypeIndex(FieldName: "FunctionType", TI: Func.getFunctionType());
224 W->printString(Label: "Name", Value: Func.getName());
225 return Error::success();
226}
227
228Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) {
229 W->printString(Label: "Guid", Value: formatv(Fmt: "{0}", Vals: TS.getGuid()).str());
230 W->printNumber(Label: "Age", Value: TS.getAge());
231 W->printString(Label: "Name", Value: TS.getName());
232 return Error::success();
233}
234
235Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) {
236 printTypeIndex(FieldName: "PointeeType", TI: Ptr.getReferentType());
237 W->printEnum(Label: "PtrType", Value: unsigned(Ptr.getPointerKind()), EnumValues: getPtrKindNames());
238 W->printEnum(Label: "PtrMode", Value: unsigned(Ptr.getMode()), EnumValues: getPtrModeNames());
239
240 W->printNumber(Label: "IsFlat", Value: Ptr.isFlat());
241 W->printNumber(Label: "IsConst", Value: Ptr.isConst());
242 W->printNumber(Label: "IsVolatile", Value: Ptr.isVolatile());
243 W->printNumber(Label: "IsUnaligned", Value: Ptr.isUnaligned());
244 W->printNumber(Label: "IsRestrict", Value: Ptr.isRestrict());
245 W->printNumber(Label: "IsThisPtr&", Value: Ptr.isLValueReferenceThisPtr());
246 W->printNumber(Label: "IsThisPtr&&", Value: Ptr.isRValueReferenceThisPtr());
247 W->printNumber(Label: "SizeOf", Value: Ptr.getSize());
248
249 if (Ptr.isPointerToMember()) {
250 const MemberPointerInfo &MI = Ptr.getMemberInfo();
251
252 printTypeIndex(FieldName: "ClassType", TI: MI.getContainingType());
253 W->printEnum(Label: "Representation", Value: uint16_t(MI.getRepresentation()),
254 EnumValues: getPtrMemberRepNames());
255 }
256
257 return Error::success();
258}
259
260Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) {
261 uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
262 printTypeIndex(FieldName: "ModifiedType", TI: Mod.getModifiedType());
263 W->printFlags(Label: "Modifiers", Value: Mods, Flags: getTypeModifierNames());
264
265 return Error::success();
266}
267
268Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, BitFieldRecord &BitField) {
269 printTypeIndex(FieldName: "Type", TI: BitField.getType());
270 W->printNumber(Label: "BitSize", Value: BitField.getBitSize());
271 W->printNumber(Label: "BitOffset", Value: BitField.getBitOffset());
272 return Error::success();
273}
274
275Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
276 VFTableShapeRecord &Shape) {
277 W->printNumber(Label: "VFEntryCount", Value: Shape.getEntryCount());
278 return Error::success();
279}
280
281Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
282 UdtSourceLineRecord &Line) {
283 printTypeIndex(FieldName: "UDT", TI: Line.getUDT());
284 printItemIndex(FieldName: "SourceFile", TI: Line.getSourceFile());
285 W->printNumber(Label: "LineNumber", Value: Line.getLineNumber());
286 return Error::success();
287}
288
289Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
290 UdtModSourceLineRecord &Line) {
291 printTypeIndex(FieldName: "UDT", TI: Line.getUDT());
292 printItemIndex(FieldName: "SourceFile", TI: Line.getSourceFile());
293 W->printNumber(Label: "LineNumber", Value: Line.getLineNumber());
294 W->printNumber(Label: "Module", Value: Line.getModule());
295 return Error::success();
296}
297
298Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, BuildInfoRecord &Args) {
299 W->printNumber(Label: "NumArgs", Value: static_cast<uint32_t>(Args.getArgs().size()));
300
301 ListScope Arguments(*W, "Arguments");
302 for (auto Arg : Args.getArgs()) {
303 printItemIndex(FieldName: "ArgType", TI: Arg);
304 }
305 return Error::success();
306}
307
308void TypeDumpVisitor::printMemberAttributes(MemberAttributes Attrs) {
309 return printMemberAttributes(Access: Attrs.getAccess(), Kind: Attrs.getMethodKind(),
310 Options: Attrs.getFlags());
311}
312
313void TypeDumpVisitor::printMemberAttributes(MemberAccess Access,
314 MethodKind Kind,
315 MethodOptions Options) {
316 W->printEnum(Label: "AccessSpecifier", Value: uint8_t(Access), EnumValues: getMemberAccessNames());
317 // Data members will be vanilla. Don't try to print a method kind for them.
318 if (Kind != MethodKind::Vanilla)
319 W->printEnum(Label: "MethodKind", Value: unsigned(Kind), EnumValues: getMemberKindNames());
320 if (Options != MethodOptions::None) {
321 W->printFlags(Label: "MethodOptions", Value: unsigned(Options), Flags: getMethodOptionNames());
322 }
323}
324
325Error TypeDumpVisitor::visitUnknownMember(CVMemberRecord &Record) {
326 W->printHex(Label: "UnknownMember", Value: unsigned(Record.Kind));
327 return Error::success();
328}
329
330Error TypeDumpVisitor::visitUnknownType(CVType &Record) {
331 W->printEnum(Label: "Kind", Value: uint16_t(Record.kind()), EnumValues: getTypeLeafNames());
332 W->printNumber(Label: "Length", Value: uint32_t(Record.content().size()));
333 return Error::success();
334}
335
336Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
337 NestedTypeRecord &Nested) {
338 printTypeIndex(FieldName: "Type", TI: Nested.getNestedType());
339 W->printString(Label: "Name", Value: Nested.getName());
340 return Error::success();
341}
342
343Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
344 OneMethodRecord &Method) {
345 MethodKind K = Method.getMethodKind();
346 printMemberAttributes(Access: Method.getAccess(), Kind: K, Options: Method.getOptions());
347 printTypeIndex(FieldName: "Type", TI: Method.getType());
348 // If virtual, then read the vftable offset.
349 if (Method.isIntroducingVirtual())
350 W->printHex(Label: "VFTableOffset", Value: Method.getVFTableOffset());
351 W->printString(Label: "Name", Value: Method.getName());
352 return Error::success();
353}
354
355Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
356 OverloadedMethodRecord &Method) {
357 W->printHex(Label: "MethodCount", Value: Method.getNumOverloads());
358 printTypeIndex(FieldName: "MethodListIndex", TI: Method.getMethodList());
359 W->printString(Label: "Name", Value: Method.getName());
360 return Error::success();
361}
362
363Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
364 DataMemberRecord &Field) {
365 printMemberAttributes(Access: Field.getAccess(), Kind: MethodKind::Vanilla,
366 Options: MethodOptions::None);
367 printTypeIndex(FieldName: "Type", TI: Field.getType());
368 W->printHex(Label: "FieldOffset", Value: Field.getFieldOffset());
369 W->printString(Label: "Name", Value: Field.getName());
370 return Error::success();
371}
372
373Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
374 StaticDataMemberRecord &Field) {
375 printMemberAttributes(Access: Field.getAccess(), Kind: MethodKind::Vanilla,
376 Options: MethodOptions::None);
377 printTypeIndex(FieldName: "Type", TI: Field.getType());
378 W->printString(Label: "Name", Value: Field.getName());
379 return Error::success();
380}
381
382Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
383 VFPtrRecord &VFTable) {
384 printTypeIndex(FieldName: "Type", TI: VFTable.getType());
385 return Error::success();
386}
387
388Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
389 EnumeratorRecord &Enum) {
390 printMemberAttributes(Access: Enum.getAccess(), Kind: MethodKind::Vanilla,
391 Options: MethodOptions::None);
392 W->printNumber(Label: "EnumValue", Value: Enum.getValue());
393 W->printString(Label: "Name", Value: Enum.getName());
394 return Error::success();
395}
396
397Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
398 BaseClassRecord &Base) {
399 printMemberAttributes(Access: Base.getAccess(), Kind: MethodKind::Vanilla,
400 Options: MethodOptions::None);
401 printTypeIndex(FieldName: "BaseType", TI: Base.getBaseType());
402 W->printHex(Label: "BaseOffset", Value: Base.getBaseOffset());
403 return Error::success();
404}
405
406Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
407 VirtualBaseClassRecord &Base) {
408 printMemberAttributes(Access: Base.getAccess(), Kind: MethodKind::Vanilla,
409 Options: MethodOptions::None);
410 printTypeIndex(FieldName: "BaseType", TI: Base.getBaseType());
411 printTypeIndex(FieldName: "VBPtrType", TI: Base.getVBPtrType());
412 W->printHex(Label: "VBPtrOffset", Value: Base.getVBPtrOffset());
413 W->printHex(Label: "VBTableIndex", Value: Base.getVTableIndex());
414 return Error::success();
415}
416
417Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
418 ListContinuationRecord &Cont) {
419 printTypeIndex(FieldName: "ContinuationIndex", TI: Cont.getContinuationIndex());
420 return Error::success();
421}
422
423Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, LabelRecord &LR) {
424 W->printEnum(Label: "Mode", Value: uint16_t(LR.Mode), EnumValues: getLabelTypeEnum());
425 return Error::success();
426}
427
428Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
429 PrecompRecord &Precomp) {
430 W->printHex(Label: "StartIndex", Value: Precomp.getStartTypeIndex());
431 W->printHex(Label: "Count", Value: Precomp.getTypesCount());
432 W->printHex(Label: "Signature", Value: Precomp.getSignature());
433 W->printString(Label: "PrecompFile", Value: Precomp.getPrecompFilePath());
434 return Error::success();
435}
436
437Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
438 EndPrecompRecord &EndPrecomp) {
439 W->printHex(Label: "Signature", Value: EndPrecomp.getSignature());
440 return Error::success();
441}
442