1 //===- MinimalSymbolDumper.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 "MinimalSymbolDumper.h"
11 #include "llvm/ADT/StringExtras.h"
12 #include "llvm/DebugInfo/CodeView/CVRecord.h"
13 #include "llvm/DebugInfo/CodeView/CodeView.h"
14 #include "llvm/DebugInfo/CodeView/Formatters.h"
15 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
16 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
17 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
18 #include "llvm/DebugInfo/PDB/Native/FormatUtil.h"
19 #include "llvm/DebugInfo/PDB/Native/InputFile.h"
20 #include "llvm/DebugInfo/PDB/Native/LinePrinter.h"
21 #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
22 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
23 #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
24 #include "llvm/Object/COFF.h"
25 #include "llvm/Support/FormatVariadic.h"
28 using namespace llvm::codeview
;
29 using namespace llvm::pdb
;
31 static std::string
formatLocalSymFlags(uint32_t IndentLevel
,
32 LocalSymFlags Flags
) {
33 std::vector
<std::string
> Opts
;
34 if (Flags
== LocalSymFlags::None
)
37 PUSH_FLAG(LocalSymFlags
, IsParameter
, Flags
, "param");
38 PUSH_FLAG(LocalSymFlags
, IsAddressTaken
, Flags
, "address is taken");
39 PUSH_FLAG(LocalSymFlags
, IsCompilerGenerated
, Flags
, "compiler generated");
40 PUSH_FLAG(LocalSymFlags
, IsAggregate
, Flags
, "aggregate");
41 PUSH_FLAG(LocalSymFlags
, IsAggregated
, Flags
, "aggregated");
42 PUSH_FLAG(LocalSymFlags
, IsAliased
, Flags
, "aliased");
43 PUSH_FLAG(LocalSymFlags
, IsAlias
, Flags
, "alias");
44 PUSH_FLAG(LocalSymFlags
, IsReturnValue
, Flags
, "return val");
45 PUSH_FLAG(LocalSymFlags
, IsOptimizedOut
, Flags
, "optimized away");
46 PUSH_FLAG(LocalSymFlags
, IsEnregisteredGlobal
, Flags
, "enreg global");
47 PUSH_FLAG(LocalSymFlags
, IsEnregisteredStatic
, Flags
, "enreg static");
48 return typesetItemList(Opts
, 4, IndentLevel
, " | ");
51 static std::string
formatExportFlags(uint32_t IndentLevel
, ExportFlags Flags
) {
52 std::vector
<std::string
> Opts
;
53 if (Flags
== ExportFlags::None
)
56 PUSH_FLAG(ExportFlags
, IsConstant
, Flags
, "constant");
57 PUSH_FLAG(ExportFlags
, IsData
, Flags
, "data");
58 PUSH_FLAG(ExportFlags
, IsPrivate
, Flags
, "private");
59 PUSH_FLAG(ExportFlags
, HasNoName
, Flags
, "no name");
60 PUSH_FLAG(ExportFlags
, HasExplicitOrdinal
, Flags
, "explicit ord");
61 PUSH_FLAG(ExportFlags
, IsForwarder
, Flags
, "forwarder");
63 return typesetItemList(Opts
, 4, IndentLevel
, " | ");
66 static std::string
formatCompileSym2Flags(uint32_t IndentLevel
,
67 CompileSym2Flags Flags
) {
68 std::vector
<std::string
> Opts
;
69 Flags
&= ~CompileSym2Flags::SourceLanguageMask
;
70 if (Flags
== CompileSym2Flags::None
)
73 PUSH_FLAG(CompileSym2Flags
, EC
, Flags
, "edit and continue");
74 PUSH_FLAG(CompileSym2Flags
, NoDbgInfo
, Flags
, "no dbg info");
75 PUSH_FLAG(CompileSym2Flags
, LTCG
, Flags
, "ltcg");
76 PUSH_FLAG(CompileSym2Flags
, NoDataAlign
, Flags
, "no data align");
77 PUSH_FLAG(CompileSym2Flags
, ManagedPresent
, Flags
, "has managed code");
78 PUSH_FLAG(CompileSym2Flags
, SecurityChecks
, Flags
, "security checks");
79 PUSH_FLAG(CompileSym2Flags
, HotPatch
, Flags
, "hot patchable");
80 PUSH_FLAG(CompileSym2Flags
, CVTCIL
, Flags
, "cvtcil");
81 PUSH_FLAG(CompileSym2Flags
, MSILModule
, Flags
, "msil module");
82 return typesetItemList(Opts
, 4, IndentLevel
, " | ");
85 static std::string
formatCompileSym3Flags(uint32_t IndentLevel
,
86 CompileSym3Flags Flags
) {
87 std::vector
<std::string
> Opts
;
88 Flags
&= ~CompileSym3Flags::SourceLanguageMask
;
90 if (Flags
== CompileSym3Flags::None
)
93 PUSH_FLAG(CompileSym3Flags
, EC
, Flags
, "edit and continue");
94 PUSH_FLAG(CompileSym3Flags
, NoDbgInfo
, Flags
, "no dbg info");
95 PUSH_FLAG(CompileSym3Flags
, LTCG
, Flags
, "ltcg");
96 PUSH_FLAG(CompileSym3Flags
, NoDataAlign
, Flags
, "no data align");
97 PUSH_FLAG(CompileSym3Flags
, ManagedPresent
, Flags
, "has managed code");
98 PUSH_FLAG(CompileSym3Flags
, SecurityChecks
, Flags
, "security checks");
99 PUSH_FLAG(CompileSym3Flags
, HotPatch
, Flags
, "hot patchable");
100 PUSH_FLAG(CompileSym3Flags
, CVTCIL
, Flags
, "cvtcil");
101 PUSH_FLAG(CompileSym3Flags
, MSILModule
, Flags
, "msil module");
102 PUSH_FLAG(CompileSym3Flags
, Sdl
, Flags
, "sdl");
103 PUSH_FLAG(CompileSym3Flags
, PGO
, Flags
, "pgo");
104 PUSH_FLAG(CompileSym3Flags
, Exp
, Flags
, "exp");
105 return typesetItemList(Opts
, 4, IndentLevel
, " | ");
108 static std::string
formatFrameProcedureOptions(uint32_t IndentLevel
,
109 FrameProcedureOptions FPO
) {
110 std::vector
<std::string
> Opts
;
111 if (FPO
== FrameProcedureOptions::None
)
114 PUSH_FLAG(FrameProcedureOptions
, HasAlloca
, FPO
, "has alloca");
115 PUSH_FLAG(FrameProcedureOptions
, HasSetJmp
, FPO
, "has setjmp");
116 PUSH_FLAG(FrameProcedureOptions
, HasLongJmp
, FPO
, "has longjmp");
117 PUSH_FLAG(FrameProcedureOptions
, HasInlineAssembly
, FPO
, "has inline asm");
118 PUSH_FLAG(FrameProcedureOptions
, HasExceptionHandling
, FPO
, "has eh");
119 PUSH_FLAG(FrameProcedureOptions
, MarkedInline
, FPO
, "marked inline");
120 PUSH_FLAG(FrameProcedureOptions
, HasStructuredExceptionHandling
, FPO
,
122 PUSH_FLAG(FrameProcedureOptions
, Naked
, FPO
, "naked");
123 PUSH_FLAG(FrameProcedureOptions
, SecurityChecks
, FPO
, "secure checks");
124 PUSH_FLAG(FrameProcedureOptions
, AsynchronousExceptionHandling
, FPO
,
126 PUSH_FLAG(FrameProcedureOptions
, NoStackOrderingForSecurityChecks
, FPO
,
128 PUSH_FLAG(FrameProcedureOptions
, Inlined
, FPO
, "inlined");
129 PUSH_FLAG(FrameProcedureOptions
, StrictSecurityChecks
, FPO
,
130 "strict secure checks");
131 PUSH_FLAG(FrameProcedureOptions
, SafeBuffers
, FPO
, "safe buffers");
132 PUSH_FLAG(FrameProcedureOptions
, ProfileGuidedOptimization
, FPO
, "pgo");
133 PUSH_FLAG(FrameProcedureOptions
, ValidProfileCounts
, FPO
,
134 "has profile counts");
135 PUSH_FLAG(FrameProcedureOptions
, OptimizedForSpeed
, FPO
, "opt speed");
136 PUSH_FLAG(FrameProcedureOptions
, GuardCfg
, FPO
, "guard cfg");
137 PUSH_FLAG(FrameProcedureOptions
, GuardCfw
, FPO
, "guard cfw");
138 return typesetItemList(Opts
, 4, IndentLevel
, " | ");
141 static std::string
formatPublicSymFlags(uint32_t IndentLevel
,
142 PublicSymFlags Flags
) {
143 std::vector
<std::string
> Opts
;
144 if (Flags
== PublicSymFlags::None
)
147 PUSH_FLAG(PublicSymFlags
, Code
, Flags
, "code");
148 PUSH_FLAG(PublicSymFlags
, Function
, Flags
, "function");
149 PUSH_FLAG(PublicSymFlags
, Managed
, Flags
, "managed");
150 PUSH_FLAG(PublicSymFlags
, MSIL
, Flags
, "msil");
151 return typesetItemList(Opts
, 4, IndentLevel
, " | ");
154 static std::string
formatProcSymFlags(uint32_t IndentLevel
,
155 ProcSymFlags Flags
) {
156 std::vector
<std::string
> Opts
;
157 if (Flags
== ProcSymFlags::None
)
160 PUSH_FLAG(ProcSymFlags
, HasFP
, Flags
, "has fp");
161 PUSH_FLAG(ProcSymFlags
, HasIRET
, Flags
, "has iret");
162 PUSH_FLAG(ProcSymFlags
, HasFRET
, Flags
, "has fret");
163 PUSH_FLAG(ProcSymFlags
, IsNoReturn
, Flags
, "noreturn");
164 PUSH_FLAG(ProcSymFlags
, IsUnreachable
, Flags
, "unreachable");
165 PUSH_FLAG(ProcSymFlags
, HasCustomCallingConv
, Flags
, "custom calling conv");
166 PUSH_FLAG(ProcSymFlags
, IsNoInline
, Flags
, "noinline");
167 PUSH_FLAG(ProcSymFlags
, HasOptimizedDebugInfo
, Flags
, "opt debuginfo");
168 return typesetItemList(Opts
, 4, IndentLevel
, " | ");
171 static std::string
formatThunkOrdinal(ThunkOrdinal Ordinal
) {
173 RETURN_CASE(ThunkOrdinal
, Standard
, "thunk");
174 RETURN_CASE(ThunkOrdinal
, ThisAdjustor
, "this adjustor");
175 RETURN_CASE(ThunkOrdinal
, Vcall
, "vcall");
176 RETURN_CASE(ThunkOrdinal
, Pcode
, "pcode");
177 RETURN_CASE(ThunkOrdinal
, UnknownLoad
, "unknown load");
178 RETURN_CASE(ThunkOrdinal
, TrampIncremental
, "tramp incremental");
179 RETURN_CASE(ThunkOrdinal
, BranchIsland
, "branch island");
181 return formatUnknownEnum(Ordinal
);
184 static std::string
formatTrampolineType(TrampolineType Tramp
) {
186 RETURN_CASE(TrampolineType
, TrampIncremental
, "tramp incremental");
187 RETURN_CASE(TrampolineType
, BranchIsland
, "branch island");
189 return formatUnknownEnum(Tramp
);
192 static std::string
formatSourceLanguage(SourceLanguage Lang
) {
194 RETURN_CASE(SourceLanguage
, C
, "c");
195 RETURN_CASE(SourceLanguage
, Cpp
, "c++");
196 RETURN_CASE(SourceLanguage
, Fortran
, "fortran");
197 RETURN_CASE(SourceLanguage
, Masm
, "masm");
198 RETURN_CASE(SourceLanguage
, Pascal
, "pascal");
199 RETURN_CASE(SourceLanguage
, Basic
, "basic");
200 RETURN_CASE(SourceLanguage
, Cobol
, "cobol");
201 RETURN_CASE(SourceLanguage
, Link
, "link");
202 RETURN_CASE(SourceLanguage
, VB
, "vb");
203 RETURN_CASE(SourceLanguage
, Cvtres
, "cvtres");
204 RETURN_CASE(SourceLanguage
, Cvtpgd
, "cvtpgd");
205 RETURN_CASE(SourceLanguage
, CSharp
, "c#");
206 RETURN_CASE(SourceLanguage
, ILAsm
, "il asm");
207 RETURN_CASE(SourceLanguage
, Java
, "java");
208 RETURN_CASE(SourceLanguage
, JScript
, "javascript");
209 RETURN_CASE(SourceLanguage
, MSIL
, "msil");
210 RETURN_CASE(SourceLanguage
, HLSL
, "hlsl");
211 RETURN_CASE(SourceLanguage
, D
, "d");
212 RETURN_CASE(SourceLanguage
, Swift
, "swift");
213 RETURN_CASE(SourceLanguage
, Rust
, "rust");
214 RETURN_CASE(SourceLanguage
, ObjC
, "objc");
215 RETURN_CASE(SourceLanguage
, ObjCpp
, "objc++");
216 RETURN_CASE(SourceLanguage
, AliasObj
, "aliasobj");
217 RETURN_CASE(SourceLanguage
, Go
, "go");
218 RETURN_CASE(SourceLanguage
, OldSwift
, "swift");
220 return formatUnknownEnum(Lang
);
223 static std::string
formatMachineType(CPUType Cpu
) {
225 RETURN_CASE(CPUType
, Intel8080
, "intel 8080");
226 RETURN_CASE(CPUType
, Intel8086
, "intel 8086");
227 RETURN_CASE(CPUType
, Intel80286
, "intel 80286");
228 RETURN_CASE(CPUType
, Intel80386
, "intel 80386");
229 RETURN_CASE(CPUType
, Intel80486
, "intel 80486");
230 RETURN_CASE(CPUType
, Pentium
, "intel pentium");
231 RETURN_CASE(CPUType
, PentiumPro
, "intel pentium pro");
232 RETURN_CASE(CPUType
, Pentium3
, "intel pentium 3");
233 RETURN_CASE(CPUType
, MIPS
, "mips");
234 RETURN_CASE(CPUType
, MIPS16
, "mips-16");
235 RETURN_CASE(CPUType
, MIPS32
, "mips-32");
236 RETURN_CASE(CPUType
, MIPS64
, "mips-64");
237 RETURN_CASE(CPUType
, MIPSI
, "mips i");
238 RETURN_CASE(CPUType
, MIPSII
, "mips ii");
239 RETURN_CASE(CPUType
, MIPSIII
, "mips iii");
240 RETURN_CASE(CPUType
, MIPSIV
, "mips iv");
241 RETURN_CASE(CPUType
, MIPSV
, "mips v");
242 RETURN_CASE(CPUType
, M68000
, "motorola 68000");
243 RETURN_CASE(CPUType
, M68010
, "motorola 68010");
244 RETURN_CASE(CPUType
, M68020
, "motorola 68020");
245 RETURN_CASE(CPUType
, M68030
, "motorola 68030");
246 RETURN_CASE(CPUType
, M68040
, "motorola 68040");
247 RETURN_CASE(CPUType
, Alpha
, "alpha");
248 RETURN_CASE(CPUType
, Alpha21164
, "alpha 21164");
249 RETURN_CASE(CPUType
, Alpha21164A
, "alpha 21164a");
250 RETURN_CASE(CPUType
, Alpha21264
, "alpha 21264");
251 RETURN_CASE(CPUType
, Alpha21364
, "alpha 21364");
252 RETURN_CASE(CPUType
, PPC601
, "powerpc 601");
253 RETURN_CASE(CPUType
, PPC603
, "powerpc 603");
254 RETURN_CASE(CPUType
, PPC604
, "powerpc 604");
255 RETURN_CASE(CPUType
, PPC620
, "powerpc 620");
256 RETURN_CASE(CPUType
, PPCFP
, "powerpc fp");
257 RETURN_CASE(CPUType
, PPCBE
, "powerpc be");
258 RETURN_CASE(CPUType
, SH3
, "sh3");
259 RETURN_CASE(CPUType
, SH3E
, "sh3e");
260 RETURN_CASE(CPUType
, SH3DSP
, "sh3 dsp");
261 RETURN_CASE(CPUType
, SH4
, "sh4");
262 RETURN_CASE(CPUType
, SHMedia
, "shmedia");
263 RETURN_CASE(CPUType
, ARM3
, "arm 3");
264 RETURN_CASE(CPUType
, ARM4
, "arm 4");
265 RETURN_CASE(CPUType
, ARM4T
, "arm 4t");
266 RETURN_CASE(CPUType
, ARM5
, "arm 5");
267 RETURN_CASE(CPUType
, ARM5T
, "arm 5t");
268 RETURN_CASE(CPUType
, ARM6
, "arm 6");
269 RETURN_CASE(CPUType
, ARM_XMAC
, "arm xmac");
270 RETURN_CASE(CPUType
, ARM_WMMX
, "arm wmmx");
271 RETURN_CASE(CPUType
, ARM7
, "arm 7");
272 RETURN_CASE(CPUType
, ARM64
, "arm64");
273 RETURN_CASE(CPUType
, ARM64EC
, "arm64ec");
274 RETURN_CASE(CPUType
, ARM64X
, "arm64x");
275 RETURN_CASE(CPUType
, HybridX86ARM64
, "hybrid x86 arm64");
276 RETURN_CASE(CPUType
, Omni
, "omni");
277 RETURN_CASE(CPUType
, Ia64
, "intel itanium ia64");
278 RETURN_CASE(CPUType
, Ia64_2
, "intel itanium ia64 2");
279 RETURN_CASE(CPUType
, CEE
, "cee");
280 RETURN_CASE(CPUType
, AM33
, "am33");
281 RETURN_CASE(CPUType
, M32R
, "m32r");
282 RETURN_CASE(CPUType
, TriCore
, "tri-core");
283 RETURN_CASE(CPUType
, X64
, "intel x86-x64");
284 RETURN_CASE(CPUType
, EBC
, "ebc");
285 RETURN_CASE(CPUType
, Thumb
, "thumb");
286 RETURN_CASE(CPUType
, ARMNT
, "arm nt");
287 RETURN_CASE(CPUType
, D3D11_Shader
, "d3d11 shader");
288 RETURN_CASE(CPUType
, Unknown
, "unknown");
290 return formatUnknownEnum(Cpu
);
293 static std::string
formatCookieKind(FrameCookieKind Kind
) {
295 RETURN_CASE(FrameCookieKind
, Copy
, "copy");
296 RETURN_CASE(FrameCookieKind
, XorStackPointer
, "xor stack ptr");
297 RETURN_CASE(FrameCookieKind
, XorFramePointer
, "xor frame ptr");
298 RETURN_CASE(FrameCookieKind
, XorR13
, "xor rot13");
300 return formatUnknownEnum(Kind
);
303 static std::string
formatRegisterId(RegisterId Id
, CPUType Cpu
) {
304 if (Cpu
== CPUType::ARMNT
) {
306 #define CV_REGISTERS_ARM
307 #define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name)
308 #include "llvm/DebugInfo/CodeView/CodeViewRegisters.def"
310 #undef CV_REGISTERS_ARM
315 } else if (Cpu
== CPUType::ARM64
) {
317 #define CV_REGISTERS_ARM64
318 #define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name)
319 #include "llvm/DebugInfo/CodeView/CodeViewRegisters.def"
321 #undef CV_REGISTERS_ARM64
328 #define CV_REGISTERS_X86
329 #define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name)
330 #include "llvm/DebugInfo/CodeView/CodeViewRegisters.def"
332 #undef CV_REGISTERS_X86
338 return formatUnknownEnum(Id
);
341 static std::string
formatRegisterId(uint16_t Reg16
, CPUType Cpu
) {
342 return formatRegisterId(RegisterId(Reg16
), Cpu
);
345 static std::string
formatRegisterId(ulittle16_t
&Reg16
, CPUType Cpu
) {
346 return formatRegisterId(uint16_t(Reg16
), Cpu
);
349 static std::string
formatRange(LocalVariableAddrRange Range
) {
350 return formatv("[{0},+{1})",
351 formatSegmentOffset(Range
.ISectStart
, Range
.OffsetStart
),
356 static std::string
formatGaps(uint32_t IndentLevel
,
357 ArrayRef
<LocalVariableAddrGap
> Gaps
) {
358 std::vector
<std::string
> GapStrs
;
359 for (const auto &G
: Gaps
) {
360 GapStrs
.push_back(formatv("({0},{1})", G
.GapStartOffset
, G
.Range
).str());
362 return typesetItemList(GapStrs
, 7, IndentLevel
, ", ");
365 static std::string
formatJumpTableEntrySize(JumpTableEntrySize EntrySize
) {
367 RETURN_CASE(JumpTableEntrySize
, Int8
, "int8");
368 RETURN_CASE(JumpTableEntrySize
, UInt8
, "uin8");
369 RETURN_CASE(JumpTableEntrySize
, Int16
, "int16");
370 RETURN_CASE(JumpTableEntrySize
, UInt16
, "uint16");
371 RETURN_CASE(JumpTableEntrySize
, Int32
, "int32");
372 RETURN_CASE(JumpTableEntrySize
, UInt32
, "uint32");
373 RETURN_CASE(JumpTableEntrySize
, Pointer
, "pointer");
374 RETURN_CASE(JumpTableEntrySize
, UInt8ShiftLeft
, "uint8shl");
375 RETURN_CASE(JumpTableEntrySize
, UInt16ShiftLeft
, "uint16shl");
376 RETURN_CASE(JumpTableEntrySize
, Int8ShiftLeft
, "int8shl");
377 RETURN_CASE(JumpTableEntrySize
, Int16ShiftLeft
, "int16shl");
379 return formatUnknownEnum(EntrySize
);
382 Error
MinimalSymbolDumper::visitSymbolBegin(codeview::CVSymbol
&Record
) {
383 return visitSymbolBegin(Record
, 0);
386 Error
MinimalSymbolDumper::visitSymbolBegin(codeview::CVSymbol
&Record
,
388 // formatLine puts the newline at the beginning, so we use formatLine here
389 // to start a new line, and then individual visit methods use format to
390 // append to the existing line.
391 P
.formatLine("{0} | {1} [size = {2}]",
392 fmt_align(Offset
, AlignStyle::Right
, 6),
393 formatSymbolKind(Record
.kind()), Record
.length());
395 return Error::success();
398 Error
MinimalSymbolDumper::visitSymbolEnd(CVSymbol
&Record
) {
400 AutoIndent
Indent(P
, 7);
401 P
.formatBinary("bytes", Record
.content(), 0);
404 return Error::success();
407 std::string
MinimalSymbolDumper::typeOrIdIndex(codeview::TypeIndex TI
,
409 if (TI
.isSimple() || TI
.isDecoratedItemId())
410 return formatv("{0}", TI
).str();
411 auto &Container
= IsType
? Types
: Ids
;
412 StringRef Name
= Container
.getTypeName(TI
);
413 if (Name
.size() > 32) {
414 Name
= Name
.take_front(32);
415 return std::string(formatv("{0} ({1}...)", TI
, Name
));
417 return std::string(formatv("{0} ({1})", TI
, Name
));
420 std::string
MinimalSymbolDumper::idIndex(codeview::TypeIndex TI
) const {
421 return typeOrIdIndex(TI
, false);
424 std::string
MinimalSymbolDumper::typeIndex(TypeIndex TI
) const {
425 return typeOrIdIndex(TI
, true);
428 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
, BlockSym
&Block
) {
429 P
.format(" `{0}`", Block
.Name
);
430 AutoIndent
Indent(P
, 7);
431 P
.formatLine("parent = {0}, end = {1}", Block
.Parent
, Block
.End
);
432 P
.formatLine("code size = {0}, addr = {1}", Block
.CodeSize
,
433 formatSegmentOffset(Block
.Segment
, Block
.CodeOffset
));
434 return Error::success();
437 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
, Thunk32Sym
&Thunk
) {
438 P
.format(" `{0}`", Thunk
.Name
);
439 AutoIndent
Indent(P
, 7);
440 P
.formatLine("parent = {0}, end = {1}, next = {2}", Thunk
.Parent
, Thunk
.End
,
442 P
.formatLine("kind = {0}, size = {1}, addr = {2}",
443 formatThunkOrdinal(Thunk
.Thunk
), Thunk
.Length
,
444 formatSegmentOffset(Thunk
.Segment
, Thunk
.Offset
));
446 return Error::success();
449 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
450 TrampolineSym
&Tramp
) {
451 AutoIndent
Indent(P
, 7);
452 P
.formatLine("type = {0}, size = {1}, source = {2}, target = {3}",
453 formatTrampolineType(Tramp
.Type
), Tramp
.Size
,
454 formatSegmentOffset(Tramp
.ThunkSection
, Tramp
.ThunkOffset
),
455 formatSegmentOffset(Tramp
.TargetSection
, Tramp
.ThunkOffset
));
457 return Error::success();
460 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
461 SectionSym
&Section
) {
462 P
.format(" `{0}`", Section
.Name
);
463 AutoIndent
Indent(P
, 7);
464 P
.formatLine("length = {0}, alignment = {1}, rva = {2}, section # = {3}",
465 Section
.Length
, Section
.Alignment
, Section
.Rva
,
466 Section
.SectionNumber
);
467 P
.printLine("characteristics =");
468 AutoIndent
Indent2(P
, 2);
469 P
.printLine(formatSectionCharacteristics(P
.getIndentLevel(),
470 Section
.Characteristics
, 1, "",
471 CharacteristicStyle::Descriptive
));
472 return Error::success();
475 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
, CoffGroupSym
&CG
) {
476 P
.format(" `{0}`", CG
.Name
);
477 AutoIndent
Indent(P
, 7);
478 P
.formatLine("length = {0}, addr = {1}", CG
.Size
,
479 formatSegmentOffset(CG
.Segment
, CG
.Offset
));
480 P
.printLine("characteristics =");
481 AutoIndent
Indent2(P
, 2);
482 P
.printLine(formatSectionCharacteristics(P
.getIndentLevel(),
483 CG
.Characteristics
, 1, "",
484 CharacteristicStyle::Descriptive
));
485 return Error::success();
488 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
489 BPRelativeSym
&BPRel
) {
490 P
.format(" `{0}`", BPRel
.Name
);
491 AutoIndent
Indent(P
, 7);
492 P
.formatLine("type = {0}, offset = {1}", typeIndex(BPRel
.Type
), BPRel
.Offset
);
493 return Error::success();
496 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
497 BuildInfoSym
&BuildInfo
) {
498 P
.format(" BuildId = `{0}`", BuildInfo
.BuildId
);
499 return Error::success();
502 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
503 CallSiteInfoSym
&CSI
) {
504 AutoIndent
Indent(P
, 7);
505 P
.formatLine("type = {0}, addr = {1}", typeIndex(CSI
.Type
),
506 formatSegmentOffset(CSI
.Segment
, CSI
.CodeOffset
));
507 return Error::success();
510 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
511 EnvBlockSym
&EnvBlock
) {
512 AutoIndent
Indent(P
, 7);
513 for (const auto &Entry
: EnvBlock
.Fields
) {
514 P
.formatLine("- {0}", Entry
);
516 return Error::success();
519 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
, FileStaticSym
&FS
) {
520 P
.format(" `{0}`", FS
.Name
);
521 AutoIndent
Indent(P
, 7);
523 Expected
<StringRef
> FileName
=
524 SymGroup
->getNameFromStringTable(FS
.ModFilenameOffset
);
526 P
.formatLine("type = {0}, file name = {1} ({2}), flags = {3}",
527 typeIndex(FS
.Index
), FS
.ModFilenameOffset
, *FileName
,
528 formatLocalSymFlags(P
.getIndentLevel() + 9, FS
.Flags
));
530 return Error::success();
533 P
.formatLine("type = {0}, file name offset = {1}, flags = {2}",
534 typeIndex(FS
.Index
), FS
.ModFilenameOffset
,
535 formatLocalSymFlags(P
.getIndentLevel() + 9, FS
.Flags
));
536 return Error::success();
539 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
, ExportSym
&Export
) {
540 P
.format(" `{0}`", Export
.Name
);
541 AutoIndent
Indent(P
, 7);
542 P
.formatLine("ordinal = {0}, flags = {1}", Export
.Ordinal
,
543 formatExportFlags(P
.getIndentLevel() + 9, Export
.Flags
));
544 return Error::success();
547 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
548 Compile2Sym
&Compile2
) {
549 AutoIndent
Indent(P
, 7);
550 SourceLanguage Lang
= static_cast<SourceLanguage
>(
551 Compile2
.Flags
& CompileSym2Flags::SourceLanguageMask
);
552 CompilationCPU
= Compile2
.Machine
;
553 P
.formatLine("machine = {0}, ver = {1}, language = {2}",
554 formatMachineType(Compile2
.Machine
), Compile2
.Version
,
555 formatSourceLanguage(Lang
));
556 P
.formatLine("frontend = {0}.{1}.{2}, backend = {3}.{4}.{5}",
557 Compile2
.VersionFrontendMajor
, Compile2
.VersionFrontendMinor
,
558 Compile2
.VersionFrontendBuild
, Compile2
.VersionBackendMajor
,
559 Compile2
.VersionBackendMinor
, Compile2
.VersionBackendBuild
);
560 P
.formatLine("flags = {0}",
561 formatCompileSym2Flags(P
.getIndentLevel() + 9, Compile2
.Flags
));
563 "extra strings = {0}",
564 typesetStringList(P
.getIndentLevel() + 9 + 2, Compile2
.ExtraStrings
));
565 return Error::success();
568 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
569 Compile3Sym
&Compile3
) {
570 AutoIndent
Indent(P
, 7);
571 SourceLanguage Lang
= static_cast<SourceLanguage
>(
572 Compile3
.Flags
& CompileSym3Flags::SourceLanguageMask
);
573 CompilationCPU
= Compile3
.Machine
;
574 P
.formatLine("machine = {0}, Ver = {1}, language = {2}",
575 formatMachineType(Compile3
.Machine
), Compile3
.Version
,
576 formatSourceLanguage(Lang
));
577 P
.formatLine("frontend = {0}.{1}.{2}.{3}, backend = {4}.{5}.{6}.{7}",
578 Compile3
.VersionFrontendMajor
, Compile3
.VersionFrontendMinor
,
579 Compile3
.VersionFrontendBuild
, Compile3
.VersionFrontendQFE
,
580 Compile3
.VersionBackendMajor
, Compile3
.VersionBackendMinor
,
581 Compile3
.VersionBackendBuild
, Compile3
.VersionBackendQFE
);
582 P
.formatLine("flags = {0}",
583 formatCompileSym3Flags(P
.getIndentLevel() + 9, Compile3
.Flags
));
584 return Error::success();
587 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
588 ConstantSym
&Constant
) {
589 P
.format(" `{0}`", Constant
.Name
);
590 AutoIndent
Indent(P
, 7);
591 P
.formatLine("type = {0}, value = {1}", typeIndex(Constant
.Type
),
592 toString(Constant
.Value
, 10));
593 return Error::success();
596 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
, DataSym
&Data
) {
597 P
.format(" `{0}`", Data
.Name
);
598 AutoIndent
Indent(P
, 7);
599 P
.formatLine("type = {0}, addr = {1}", typeIndex(Data
.Type
),
600 formatSegmentOffset(Data
.Segment
, Data
.DataOffset
));
601 return Error::success();
604 Error
MinimalSymbolDumper::visitKnownRecord(
605 CVSymbol
&CVR
, DefRangeFramePointerRelFullScopeSym
&Def
) {
606 P
.format(" offset = {0}", Def
.Offset
);
607 return Error::success();
610 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
611 DefRangeFramePointerRelSym
&Def
) {
612 AutoIndent
Indent(P
, 7);
613 P
.formatLine("offset = {0}, range = {1}", Def
.Hdr
.Offset
,
614 formatRange(Def
.Range
));
615 P
.formatLine("gaps = [{0}]", formatGaps(P
.getIndentLevel() + 9, Def
.Gaps
));
616 return Error::success();
619 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
620 DefRangeRegisterRelSym
&Def
) {
621 AutoIndent
Indent(P
, 7);
622 P
.formatLine("register = {0}, offset = {1}, offset in parent = {2}, has "
624 formatRegisterId(Def
.Hdr
.Register
, CompilationCPU
),
625 int32_t(Def
.Hdr
.BasePointerOffset
), Def
.offsetInParent(),
626 Def
.hasSpilledUDTMember());
627 P
.formatLine("range = {0}, gaps = [{1}]", formatRange(Def
.Range
),
628 formatGaps(P
.getIndentLevel() + 9, Def
.Gaps
));
629 return Error::success();
632 Error
MinimalSymbolDumper::visitKnownRecord(
633 CVSymbol
&CVR
, DefRangeRegisterSym
&DefRangeRegister
) {
634 AutoIndent
Indent(P
, 7);
635 P
.formatLine("register = {0}, may have no name = {1}, range start = "
637 formatRegisterId(DefRangeRegister
.Hdr
.Register
, CompilationCPU
),
638 bool(DefRangeRegister
.Hdr
.MayHaveNoName
),
639 formatSegmentOffset(DefRangeRegister
.Range
.ISectStart
,
640 DefRangeRegister
.Range
.OffsetStart
),
641 DefRangeRegister
.Range
.Range
);
642 P
.formatLine("gaps = [{0}]",
643 formatGaps(P
.getIndentLevel() + 9, DefRangeRegister
.Gaps
));
644 return Error::success();
647 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
648 DefRangeSubfieldRegisterSym
&Def
) {
649 AutoIndent
Indent(P
, 7);
650 bool NoName
= !!(Def
.Hdr
.MayHaveNoName
== 0);
651 P
.formatLine("register = {0}, may have no name = {1}, offset in parent = {2}",
652 formatRegisterId(Def
.Hdr
.Register
, CompilationCPU
), NoName
,
653 uint32_t(Def
.Hdr
.OffsetInParent
));
654 P
.formatLine("range = {0}, gaps = [{1}]", formatRange(Def
.Range
),
655 formatGaps(P
.getIndentLevel() + 9, Def
.Gaps
));
656 return Error::success();
659 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
660 DefRangeSubfieldSym
&Def
) {
661 AutoIndent
Indent(P
, 7);
662 P
.formatLine("program = {0}, offset in parent = {1}, range = {2}",
663 Def
.Program
, Def
.OffsetInParent
, formatRange(Def
.Range
));
664 P
.formatLine("gaps = [{0}]", formatGaps(P
.getIndentLevel() + 9, Def
.Gaps
));
665 return Error::success();
668 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
, DefRangeSym
&Def
) {
669 AutoIndent
Indent(P
, 7);
670 P
.formatLine("program = {0}, range = {1}", Def
.Program
,
671 formatRange(Def
.Range
));
672 P
.formatLine("gaps = [{0}]", formatGaps(P
.getIndentLevel() + 9, Def
.Gaps
));
673 return Error::success();
676 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
, FrameCookieSym
&FC
) {
677 AutoIndent
Indent(P
, 7);
678 P
.formatLine("code offset = {0}, Register = {1}, kind = {2}, flags = {3}",
679 FC
.CodeOffset
, formatRegisterId(FC
.Register
, CompilationCPU
),
680 formatCookieKind(FC
.CookieKind
), FC
.Flags
);
681 return Error::success();
684 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
, FrameProcSym
&FP
) {
685 AutoIndent
Indent(P
, 7);
686 P
.formatLine("size = {0}, padding size = {1}, offset to padding = {2}",
687 FP
.TotalFrameBytes
, FP
.PaddingFrameBytes
, FP
.OffsetToPadding
);
688 P
.formatLine("bytes of callee saved registers = {0}, exception handler addr "
690 FP
.BytesOfCalleeSavedRegisters
,
691 formatSegmentOffset(FP
.SectionIdOfExceptionHandler
,
692 FP
.OffsetOfExceptionHandler
));
694 "local fp reg = {0}, param fp reg = {1}",
695 formatRegisterId(FP
.getLocalFramePtrReg(CompilationCPU
), CompilationCPU
),
696 formatRegisterId(FP
.getParamFramePtrReg(CompilationCPU
), CompilationCPU
));
697 P
.formatLine("flags = {0}",
698 formatFrameProcedureOptions(P
.getIndentLevel() + 9, FP
.Flags
));
699 return Error::success();
702 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
703 HeapAllocationSiteSym
&HAS
) {
704 AutoIndent
Indent(P
, 7);
705 P
.formatLine("type = {0}, addr = {1} call size = {2}", typeIndex(HAS
.Type
),
706 formatSegmentOffset(HAS
.Segment
, HAS
.CodeOffset
),
707 HAS
.CallInstructionSize
);
708 return Error::success();
711 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
, InlineSiteSym
&IS
) {
712 AutoIndent
Indent(P
, 7);
713 P
.formatLine("inlinee = {0}, parent = {1}, end = {2}", idIndex(IS
.Inlinee
),
716 // Break down the annotation byte code and calculate code and line offsets.
717 // FIXME: It would be helpful if we could look up the initial file and inlinee
718 // lines offset using the inlinee index above.
719 uint32_t CodeOffset
= 0;
720 int32_t LineOffset
= 0;
721 for (auto &Annot
: IS
.annotations()) {
722 P
.formatLine(" {0}", fmt_align(toHex(Annot
.Bytes
), AlignStyle::Left
, 9));
724 auto formatCodeOffset
= [&](uint32_t Delta
) {
726 P
.format(" code 0x{0} (+0x{1})", utohexstr(CodeOffset
), utohexstr(Delta
));
728 auto formatCodeLength
= [&](uint32_t Length
) {
729 // Notably, changing the code length does not affect the code offset.
730 P
.format(" code end 0x{0} (+0x{1})", utohexstr(CodeOffset
+ Length
),
733 auto formatLineOffset
= [&](int32_t Delta
) {
735 char Sign
= Delta
> 0 ? '+' : '-';
736 P
.format(" line {0} ({1}{2})", LineOffset
, Sign
, std::abs(Delta
));
739 // Use the opcode to interpret the integer values.
740 switch (Annot
.OpCode
) {
741 case BinaryAnnotationsOpCode::Invalid
:
743 case BinaryAnnotationsOpCode::CodeOffset
:
744 case BinaryAnnotationsOpCode::ChangeCodeOffset
:
745 formatCodeOffset(Annot
.U1
);
747 case BinaryAnnotationsOpCode::ChangeLineOffset
:
748 formatLineOffset(Annot
.S1
);
750 case BinaryAnnotationsOpCode::ChangeCodeLength
:
751 formatCodeLength(Annot
.U1
);
752 // Apparently this annotation updates the code offset. It's hard to make
753 // MSVC produce this opcode, but clang uses it, and debuggers seem to use
754 // this interpretation.
755 CodeOffset
+= Annot
.U1
;
757 case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset
:
758 formatCodeOffset(Annot
.U1
);
759 formatLineOffset(Annot
.S1
);
761 case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset
:
762 formatCodeOffset(Annot
.U2
);
763 formatCodeLength(Annot
.U1
);
766 case BinaryAnnotationsOpCode::ChangeFile
: {
767 uint32_t FileOffset
= Annot
.U1
;
768 StringRef Filename
= "<unknown>";
770 if (Expected
<StringRef
> MaybeFile
=
771 SymGroup
->getNameFromStringTable(FileOffset
))
772 Filename
= *MaybeFile
;
774 return MaybeFile
.takeError();
776 P
.format(" setfile {0} 0x{1}", utohexstr(FileOffset
));
780 // The rest of these are hard to convince MSVC to emit, so they are not as
782 case BinaryAnnotationsOpCode::ChangeCodeOffsetBase
:
783 formatCodeOffset(Annot
.U1
);
785 case BinaryAnnotationsOpCode::ChangeLineEndDelta
:
786 case BinaryAnnotationsOpCode::ChangeRangeKind
:
787 case BinaryAnnotationsOpCode::ChangeColumnStart
:
788 case BinaryAnnotationsOpCode::ChangeColumnEnd
:
789 P
.format(" {0} {1}", Annot
.Name
, Annot
.U1
);
791 case BinaryAnnotationsOpCode::ChangeColumnEndDelta
:
792 P
.format(" {0} {1}", Annot
.Name
, Annot
.S1
);
796 return Error::success();
799 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
800 RegisterSym
&Register
) {
801 P
.format(" `{0}`", Register
.Name
);
802 AutoIndent
Indent(P
, 7);
803 P
.formatLine("register = {0}, type = {1}",
804 formatRegisterId(Register
.Register
, CompilationCPU
),
805 typeIndex(Register
.Index
));
806 return Error::success();
809 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
810 PublicSym32
&Public
) {
811 P
.format(" `{0}`", Public
.Name
);
812 AutoIndent
Indent(P
, 7);
813 P
.formatLine("flags = {0}, addr = {1}",
814 formatPublicSymFlags(P
.getIndentLevel() + 9, Public
.Flags
),
815 formatSegmentOffset(Public
.Segment
, Public
.Offset
));
816 return Error::success();
819 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
, ProcRefSym
&PR
) {
820 P
.format(" `{0}`", PR
.Name
);
821 AutoIndent
Indent(P
, 7);
822 P
.formatLine("module = {0}, sum name = {1}, offset = {2}", PR
.Module
,
823 PR
.SumName
, PR
.SymOffset
);
824 return Error::success();
827 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
, LabelSym
&Label
) {
828 P
.format(" `{0}` (addr = {1})", Label
.Name
,
829 formatSegmentOffset(Label
.Segment
, Label
.CodeOffset
));
830 AutoIndent
Indent(P
, 7);
831 P
.formatLine("flags = {0}",
832 formatProcSymFlags(P
.getIndentLevel() + 9, Label
.Flags
));
833 return Error::success();
836 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
, LocalSym
&Local
) {
837 P
.format(" `{0}`", Local
.Name
);
838 AutoIndent
Indent(P
, 7);
840 std::string FlagStr
=
841 formatLocalSymFlags(P
.getIndentLevel() + 9, Local
.Flags
);
842 P
.formatLine("type={0}, flags = {1}", typeIndex(Local
.Type
), FlagStr
);
843 return Error::success();
846 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
847 ObjNameSym
&ObjName
) {
848 P
.format(" sig={0}, `{1}`", ObjName
.Signature
, ObjName
.Name
);
849 return Error::success();
852 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
, ProcSym
&Proc
) {
853 P
.format(" `{0}`", Proc
.Name
);
854 AutoIndent
Indent(P
, 7);
855 P
.formatLine("parent = {0}, end = {1}, addr = {2}, code size = {3}",
856 Proc
.Parent
, Proc
.End
,
857 formatSegmentOffset(Proc
.Segment
, Proc
.CodeOffset
),
860 switch (Proc
.getKind()) {
861 case SymbolRecordKind::GlobalProcIdSym
:
862 case SymbolRecordKind::ProcIdSym
:
863 case SymbolRecordKind::DPCProcIdSym
:
869 P
.formatLine("type = `{0}`, debug start = {1}, debug end = {2}, flags = {3}",
870 typeOrIdIndex(Proc
.FunctionType
, IsType
), Proc
.DbgStart
,
872 formatProcSymFlags(P
.getIndentLevel() + 9, Proc
.Flags
));
873 return Error::success();
876 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
877 ScopeEndSym
&ScopeEnd
) {
878 return Error::success();
881 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
, CallerSym
&Caller
) {
883 switch (CVR
.kind()) {
885 Format
= "callee: {0}";
888 Format
= "caller: {0}";
891 Format
= "inlinee: {0}";
894 return llvm::make_error
<CodeViewError
>(
895 "Unknown CV Record type for a CallerSym object!");
897 AutoIndent
Indent(P
, 7);
898 for (const auto &I
: Caller
.Indices
) {
899 P
.formatLine(Format
, idIndex(I
));
901 return Error::success();
904 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
905 RegRelativeSym
&RegRel
) {
906 P
.format(" `{0}`", RegRel
.Name
);
907 AutoIndent
Indent(P
, 7);
909 "type = {0}, register = {1}, offset = {2}", typeIndex(RegRel
.Type
),
910 formatRegisterId(RegRel
.Register
, CompilationCPU
), RegRel
.Offset
);
911 return Error::success();
914 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
915 ThreadLocalDataSym
&Data
) {
916 P
.format(" `{0}`", Data
.Name
);
917 AutoIndent
Indent(P
, 7);
918 P
.formatLine("type = {0}, addr = {1}", typeIndex(Data
.Type
),
919 formatSegmentOffset(Data
.Segment
, Data
.DataOffset
));
920 return Error::success();
923 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
, UDTSym
&UDT
) {
924 P
.format(" `{0}`", UDT
.Name
);
925 AutoIndent
Indent(P
, 7);
926 P
.formatLine("original type = {0}", UDT
.Type
);
927 return Error::success();
930 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
931 UsingNamespaceSym
&UN
) {
932 P
.format(" `{0}`", UN
.Name
);
933 return Error::success();
936 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
937 AnnotationSym
&Annot
) {
938 AutoIndent
Indent(P
, 7);
939 P
.formatLine("addr = {0}", formatSegmentOffset(Annot
.Segment
, Annot
.CodeOffset
));
940 P
.formatLine("strings = {0}", typesetStringList(P
.getIndentLevel() + 9 + 2,
942 return Error::success();
945 Error
MinimalSymbolDumper::visitKnownRecord(CVSymbol
&CVR
,
946 JumpTableSym
&JumpTable
) {
947 AutoIndent
Indent(P
, 7);
949 "base = {0}, switchtype = {1}, branch = {2}, table = {3}, entriescount = "
951 formatSegmentOffset(JumpTable
.BaseSegment
, JumpTable
.BaseOffset
),
952 formatJumpTableEntrySize(JumpTable
.SwitchType
),
953 formatSegmentOffset(JumpTable
.BranchSegment
, JumpTable
.BranchOffset
),
954 formatSegmentOffset(JumpTable
.TableSegment
, JumpTable
.TableOffset
),
955 JumpTable
.EntriesCount
);
956 return Error::success();