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