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