1 //===- MinimalSymbolDumper.cpp -------------------------------- *- 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 "MinimalSymbolDumper.h" 10 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" 26 27 using namespace llvm; 28 using namespace llvm::codeview; 29 using namespace llvm::pdb; 30 31 static std::string formatLocalSymFlags(uint32_t IndentLevel, 32 LocalSymFlags Flags) { 33 std::vector<std::string> Opts; 34 if (Flags == LocalSymFlags::None) 35 return "none"; 36 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, " | "); 49 } 50 51 static std::string formatExportFlags(uint32_t IndentLevel, ExportFlags Flags) { 52 std::vector<std::string> Opts; 53 if (Flags == ExportFlags::None) 54 return "none"; 55 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"); 62 63 return typesetItemList(Opts, 4, IndentLevel, " | "); 64 } 65 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) 71 return "none"; 72 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, " | "); 83 } 84 85 static std::string formatCompileSym3Flags(uint32_t IndentLevel, 86 CompileSym3Flags Flags) { 87 std::vector<std::string> Opts; 88 Flags &= ~CompileSym3Flags::SourceLanguageMask; 89 90 if (Flags == CompileSym3Flags::None) 91 return "none"; 92 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, " | "); 106 } 107 108 static std::string formatFrameProcedureOptions(uint32_t IndentLevel, 109 FrameProcedureOptions FPO) { 110 std::vector<std::string> Opts; 111 if (FPO == FrameProcedureOptions::None) 112 return "none"; 113 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, 121 "has seh"); 122 PUSH_FLAG(FrameProcedureOptions, Naked, FPO, "naked"); 123 PUSH_FLAG(FrameProcedureOptions, SecurityChecks, FPO, "secure checks"); 124 PUSH_FLAG(FrameProcedureOptions, AsynchronousExceptionHandling, FPO, 125 "has async eh"); 126 PUSH_FLAG(FrameProcedureOptions, NoStackOrderingForSecurityChecks, FPO, 127 "no stack order"); 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, " | "); 139 } 140 141 static std::string formatPublicSymFlags(uint32_t IndentLevel, 142 PublicSymFlags Flags) { 143 std::vector<std::string> Opts; 144 if (Flags == PublicSymFlags::None) 145 return "none"; 146 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, " | "); 152 } 153 154 static std::string formatProcSymFlags(uint32_t IndentLevel, 155 ProcSymFlags Flags) { 156 std::vector<std::string> Opts; 157 if (Flags == ProcSymFlags::None) 158 return "none"; 159 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, " | "); 169 } 170 171 static std::string formatThunkOrdinal(ThunkOrdinal Ordinal) { 172 switch (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"); 180 } 181 return formatUnknownEnum(Ordinal); 182 } 183 184 static std::string formatTrampolineType(TrampolineType Tramp) { 185 switch (Tramp) { 186 RETURN_CASE(TrampolineType, TrampIncremental, "tramp incremental"); 187 RETURN_CASE(TrampolineType, BranchIsland, "branch island"); 188 } 189 return formatUnknownEnum(Tramp); 190 } 191 192 static std::string formatSourceLanguage(SourceLanguage Lang) { 193 switch (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"); 219 } 220 return formatUnknownEnum(Lang); 221 } 222 223 static std::string formatMachineType(CPUType Cpu) { 224 switch (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"); 289 } 290 return formatUnknownEnum(Cpu); 291 } 292 293 static std::string formatCookieKind(FrameCookieKind Kind) { 294 switch (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"); 299 } 300 return formatUnknownEnum(Kind); 301 } 302 303 static std::string formatRegisterId(RegisterId Id, CPUType Cpu) { 304 if (Cpu == CPUType::ARMNT) { 305 switch (Id) { 306 #define CV_REGISTERS_ARM 307 #define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name) 308 #include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" 309 #undef CV_REGISTER 310 #undef CV_REGISTERS_ARM 311 312 default: 313 break; 314 } 315 } else if (Cpu == CPUType::ARM64) { 316 switch (Id) { 317 #define CV_REGISTERS_ARM64 318 #define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name) 319 #include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" 320 #undef CV_REGISTER 321 #undef CV_REGISTERS_ARM64 322 323 default: 324 break; 325 } 326 } else { 327 switch (Id) { 328 #define CV_REGISTERS_X86 329 #define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name) 330 #include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" 331 #undef CV_REGISTER 332 #undef CV_REGISTERS_X86 333 334 default: 335 break; 336 } 337 } 338 return formatUnknownEnum(Id); 339 } 340 341 static std::string formatRegisterId(uint16_t Reg16, CPUType Cpu) { 342 return formatRegisterId(RegisterId(Reg16), Cpu); 343 } 344 345 static std::string formatRegisterId(ulittle16_t &Reg16, CPUType Cpu) { 346 return formatRegisterId(uint16_t(Reg16), Cpu); 347 } 348 349 static std::string formatRange(LocalVariableAddrRange Range) { 350 return formatv("[{0},+{1})", 351 formatSegmentOffset(Range.ISectStart, Range.OffsetStart), 352 Range.Range) 353 .str(); 354 } 355 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()); 361 } 362 return typesetItemList(GapStrs, 7, IndentLevel, ", "); 363 } 364 365 static std::string formatJumpTableEntrySize(JumpTableEntrySize EntrySize) { 366 switch (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"); 378 } 379 return formatUnknownEnum(EntrySize); 380 } 381 382 Error MinimalSymbolDumper::visitSymbolBegin(codeview::CVSymbol &Record) { 383 return visitSymbolBegin(Record, 0); 384 } 385 386 Error MinimalSymbolDumper::visitSymbolBegin(codeview::CVSymbol &Record, 387 uint32_t Offset) { 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()); 394 P.Indent(); 395 return Error::success(); 396 } 397 398 Error MinimalSymbolDumper::visitSymbolEnd(CVSymbol &Record) { 399 if (RecordBytes) { 400 AutoIndent Indent(P, 7); 401 P.formatBinary("bytes", Record.content(), 0); 402 } 403 P.Unindent(); 404 return Error::success(); 405 } 406 407 std::string MinimalSymbolDumper::typeOrIdIndex(codeview::TypeIndex TI, 408 bool IsType) const { 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)); 416 } else 417 return std::string(formatv("{0} ({1})", TI, Name)); 418 } 419 420 std::string MinimalSymbolDumper::idIndex(codeview::TypeIndex TI) const { 421 return typeOrIdIndex(TI, false); 422 } 423 424 std::string MinimalSymbolDumper::typeIndex(TypeIndex TI) const { 425 return typeOrIdIndex(TI, true); 426 } 427 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(); 435 } 436 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, 441 Thunk.Next); 442 P.formatLine("kind = {0}, size = {1}, addr = {2}", 443 formatThunkOrdinal(Thunk.Thunk), Thunk.Length, 444 formatSegmentOffset(Thunk.Segment, Thunk.Offset)); 445 446 return Error::success(); 447 } 448 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)); 456 457 return Error::success(); 458 } 459 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(); 473 } 474 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(); 486 } 487 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(); 494 } 495 496 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 497 BuildInfoSym &BuildInfo) { 498 P.format(" BuildId = `{0}`", BuildInfo.BuildId); 499 return Error::success(); 500 } 501 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(); 508 } 509 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); 515 } 516 return Error::success(); 517 } 518 519 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, FileStaticSym &FS) { 520 P.format(" `{0}`", FS.Name); 521 AutoIndent Indent(P, 7); 522 if (SymGroup) { 523 Expected<StringRef> FileName = 524 SymGroup->getNameFromStringTable(FS.ModFilenameOffset); 525 if (FileName) { 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)); 529 } 530 return Error::success(); 531 } 532 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(); 537 } 538 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(); 545 } 546 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)); 562 P.formatLine( 563 "extra strings = {0}", 564 typesetStringList(P.getIndentLevel() + 9 + 2, Compile2.ExtraStrings)); 565 return Error::success(); 566 } 567 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(); 585 } 586 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(); 594 } 595 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(); 602 } 603 604 Error MinimalSymbolDumper::visitKnownRecord( 605 CVSymbol &CVR, DefRangeFramePointerRelFullScopeSym &Def) { 606 P.format(" offset = {0}", Def.Offset); 607 return Error::success(); 608 } 609 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(); 617 } 618 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 " 623 "spilled udt = {3}", 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(); 630 } 631 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 = " 636 "{2}, length = {3}", 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(); 645 } 646 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(); 657 } 658 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(); 666 } 667 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(); 674 } 675 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(); 682 } 683 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 " 689 "= {1}", 690 FP.BytesOfCalleeSavedRegisters, 691 formatSegmentOffset(FP.SectionIdOfExceptionHandler, 692 FP.OffsetOfExceptionHandler)); 693 P.formatLine( 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(); 700 } 701 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(); 709 } 710 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), 714 IS.Parent, IS.End); 715 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)); 723 724 auto formatCodeOffset = [&](uint32_t Delta) { 725 CodeOffset += Delta; 726 P.format(" code 0x{0} (+0x{1})", utohexstr(CodeOffset), utohexstr(Delta)); 727 }; 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), 731 utohexstr(Length)); 732 }; 733 auto formatLineOffset = [&](int32_t Delta) { 734 LineOffset += Delta; 735 char Sign = Delta > 0 ? '+' : '-'; 736 P.format(" line {0} ({1}{2})", LineOffset, Sign, std::abs(Delta)); 737 }; 738 739 // Use the opcode to interpret the integer values. 740 switch (Annot.OpCode) { 741 case BinaryAnnotationsOpCode::Invalid: 742 break; 743 case BinaryAnnotationsOpCode::CodeOffset: 744 case BinaryAnnotationsOpCode::ChangeCodeOffset: 745 formatCodeOffset(Annot.U1); 746 break; 747 case BinaryAnnotationsOpCode::ChangeLineOffset: 748 formatLineOffset(Annot.S1); 749 break; 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; 756 break; 757 case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: 758 formatCodeOffset(Annot.U1); 759 formatLineOffset(Annot.S1); 760 break; 761 case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: 762 formatCodeOffset(Annot.U2); 763 formatCodeLength(Annot.U1); 764 break; 765 766 case BinaryAnnotationsOpCode::ChangeFile: { 767 uint32_t FileOffset = Annot.U1; 768 StringRef Filename = "<unknown>"; 769 if (SymGroup) { 770 if (Expected<StringRef> MaybeFile = 771 SymGroup->getNameFromStringTable(FileOffset)) 772 Filename = *MaybeFile; 773 else 774 return MaybeFile.takeError(); 775 } 776 P.format(" setfile {0} 0x{1}", utohexstr(FileOffset)); 777 break; 778 } 779 780 // The rest of these are hard to convince MSVC to emit, so they are not as 781 // well understood. 782 case BinaryAnnotationsOpCode::ChangeCodeOffsetBase: 783 formatCodeOffset(Annot.U1); 784 break; 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); 790 break; 791 case BinaryAnnotationsOpCode::ChangeColumnEndDelta: 792 P.format(" {0} {1}", Annot.Name, Annot.S1); 793 break; 794 } 795 } 796 return Error::success(); 797 } 798 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(); 807 } 808 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(); 817 } 818 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(); 825 } 826 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(); 834 } 835 836 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, LocalSym &Local) { 837 P.format(" `{0}`", Local.Name); 838 AutoIndent Indent(P, 7); 839 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(); 844 } 845 846 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 847 ObjNameSym &ObjName) { 848 P.format(" sig={0}, `{1}`", ObjName.Signature, ObjName.Name); 849 return Error::success(); 850 } 851 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), 858 Proc.CodeSize); 859 bool IsType = true; 860 switch (Proc.getKind()) { 861 case SymbolRecordKind::GlobalProcIdSym: 862 case SymbolRecordKind::ProcIdSym: 863 case SymbolRecordKind::DPCProcIdSym: 864 IsType = false; 865 break; 866 default: 867 break; 868 } 869 P.formatLine("type = `{0}`, debug start = {1}, debug end = {2}, flags = {3}", 870 typeOrIdIndex(Proc.FunctionType, IsType), Proc.DbgStart, 871 Proc.DbgEnd, 872 formatProcSymFlags(P.getIndentLevel() + 9, Proc.Flags)); 873 return Error::success(); 874 } 875 876 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 877 ScopeEndSym &ScopeEnd) { 878 return Error::success(); 879 } 880 881 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) { 882 const char *Format; 883 switch (CVR.kind()) { 884 case S_CALLEES: 885 Format = "callee: {0}"; 886 break; 887 case S_CALLERS: 888 Format = "caller: {0}"; 889 break; 890 case S_INLINEES: 891 Format = "inlinee: {0}"; 892 break; 893 default: 894 return llvm::make_error<CodeViewError>( 895 "Unknown CV Record type for a CallerSym object!"); 896 } 897 AutoIndent Indent(P, 7); 898 for (const auto &I : Caller.Indices) { 899 P.formatLine(Format, idIndex(I)); 900 } 901 return Error::success(); 902 } 903 904 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 905 RegRelativeSym &RegRel) { 906 P.format(" `{0}`", RegRel.Name); 907 AutoIndent Indent(P, 7); 908 P.formatLine( 909 "type = {0}, register = {1}, offset = {2}", typeIndex(RegRel.Type), 910 formatRegisterId(RegRel.Register, CompilationCPU), RegRel.Offset); 911 return Error::success(); 912 } 913 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(); 921 } 922 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(); 928 } 929 930 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 931 UsingNamespaceSym &UN) { 932 P.format(" `{0}`", UN.Name); 933 return Error::success(); 934 } 935 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, 941 Annot.Strings)); 942 return Error::success(); 943 } 944 945 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 946 JumpTableSym &JumpTable) { 947 AutoIndent Indent(P, 7); 948 P.formatLine( 949 "base = {0}, switchtype = {1}, branch = {2}, table = {3}, entriescount = " 950 "{4}", 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(); 957 } 958