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 } 217 return formatUnknownEnum(Lang); 218 } 219 220 static std::string formatMachineType(CPUType Cpu) { 221 switch (Cpu) { 222 RETURN_CASE(CPUType, Intel8080, "intel 8080"); 223 RETURN_CASE(CPUType, Intel8086, "intel 8086"); 224 RETURN_CASE(CPUType, Intel80286, "intel 80286"); 225 RETURN_CASE(CPUType, Intel80386, "intel 80386"); 226 RETURN_CASE(CPUType, Intel80486, "intel 80486"); 227 RETURN_CASE(CPUType, Pentium, "intel pentium"); 228 RETURN_CASE(CPUType, PentiumPro, "intel pentium pro"); 229 RETURN_CASE(CPUType, Pentium3, "intel pentium 3"); 230 RETURN_CASE(CPUType, MIPS, "mips"); 231 RETURN_CASE(CPUType, MIPS16, "mips-16"); 232 RETURN_CASE(CPUType, MIPS32, "mips-32"); 233 RETURN_CASE(CPUType, MIPS64, "mips-64"); 234 RETURN_CASE(CPUType, MIPSI, "mips i"); 235 RETURN_CASE(CPUType, MIPSII, "mips ii"); 236 RETURN_CASE(CPUType, MIPSIII, "mips iii"); 237 RETURN_CASE(CPUType, MIPSIV, "mips iv"); 238 RETURN_CASE(CPUType, MIPSV, "mips v"); 239 RETURN_CASE(CPUType, M68000, "motorola 68000"); 240 RETURN_CASE(CPUType, M68010, "motorola 68010"); 241 RETURN_CASE(CPUType, M68020, "motorola 68020"); 242 RETURN_CASE(CPUType, M68030, "motorola 68030"); 243 RETURN_CASE(CPUType, M68040, "motorola 68040"); 244 RETURN_CASE(CPUType, Alpha, "alpha"); 245 RETURN_CASE(CPUType, Alpha21164, "alpha 21164"); 246 RETURN_CASE(CPUType, Alpha21164A, "alpha 21164a"); 247 RETURN_CASE(CPUType, Alpha21264, "alpha 21264"); 248 RETURN_CASE(CPUType, Alpha21364, "alpha 21364"); 249 RETURN_CASE(CPUType, PPC601, "powerpc 601"); 250 RETURN_CASE(CPUType, PPC603, "powerpc 603"); 251 RETURN_CASE(CPUType, PPC604, "powerpc 604"); 252 RETURN_CASE(CPUType, PPC620, "powerpc 620"); 253 RETURN_CASE(CPUType, PPCFP, "powerpc fp"); 254 RETURN_CASE(CPUType, PPCBE, "powerpc be"); 255 RETURN_CASE(CPUType, SH3, "sh3"); 256 RETURN_CASE(CPUType, SH3E, "sh3e"); 257 RETURN_CASE(CPUType, SH3DSP, "sh3 dsp"); 258 RETURN_CASE(CPUType, SH4, "sh4"); 259 RETURN_CASE(CPUType, SHMedia, "shmedia"); 260 RETURN_CASE(CPUType, ARM3, "arm 3"); 261 RETURN_CASE(CPUType, ARM4, "arm 4"); 262 RETURN_CASE(CPUType, ARM4T, "arm 4t"); 263 RETURN_CASE(CPUType, ARM5, "arm 5"); 264 RETURN_CASE(CPUType, ARM5T, "arm 5t"); 265 RETURN_CASE(CPUType, ARM6, "arm 6"); 266 RETURN_CASE(CPUType, ARM_XMAC, "arm xmac"); 267 RETURN_CASE(CPUType, ARM_WMMX, "arm wmmx"); 268 RETURN_CASE(CPUType, ARM7, "arm 7"); 269 RETURN_CASE(CPUType, ARM64, "arm64"); 270 RETURN_CASE(CPUType, ARM64EC, "arm64ec"); 271 RETURN_CASE(CPUType, ARM64X, "arm64x"); 272 RETURN_CASE(CPUType, HybridX86ARM64, "hybrid x86 arm64"); 273 RETURN_CASE(CPUType, Omni, "omni"); 274 RETURN_CASE(CPUType, Ia64, "intel itanium ia64"); 275 RETURN_CASE(CPUType, Ia64_2, "intel itanium ia64 2"); 276 RETURN_CASE(CPUType, CEE, "cee"); 277 RETURN_CASE(CPUType, AM33, "am33"); 278 RETURN_CASE(CPUType, M32R, "m32r"); 279 RETURN_CASE(CPUType, TriCore, "tri-core"); 280 RETURN_CASE(CPUType, X64, "intel x86-x64"); 281 RETURN_CASE(CPUType, EBC, "ebc"); 282 RETURN_CASE(CPUType, Thumb, "thumb"); 283 RETURN_CASE(CPUType, ARMNT, "arm nt"); 284 RETURN_CASE(CPUType, D3D11_Shader, "d3d11 shader"); 285 } 286 return formatUnknownEnum(Cpu); 287 } 288 289 static std::string formatCookieKind(FrameCookieKind Kind) { 290 switch (Kind) { 291 RETURN_CASE(FrameCookieKind, Copy, "copy"); 292 RETURN_CASE(FrameCookieKind, XorStackPointer, "xor stack ptr"); 293 RETURN_CASE(FrameCookieKind, XorFramePointer, "xor frame ptr"); 294 RETURN_CASE(FrameCookieKind, XorR13, "xor rot13"); 295 } 296 return formatUnknownEnum(Kind); 297 } 298 299 static std::string formatRegisterId(RegisterId Id, CPUType Cpu) { 300 if (Cpu == CPUType::ARMNT) { 301 switch (Id) { 302 #define CV_REGISTERS_ARM 303 #define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name) 304 #include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" 305 #undef CV_REGISTER 306 #undef CV_REGISTERS_ARM 307 308 default: 309 break; 310 } 311 } else if (Cpu == CPUType::ARM64) { 312 switch (Id) { 313 #define CV_REGISTERS_ARM64 314 #define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name) 315 #include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" 316 #undef CV_REGISTER 317 #undef CV_REGISTERS_ARM64 318 319 default: 320 break; 321 } 322 } else { 323 switch (Id) { 324 #define CV_REGISTERS_X86 325 #define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name) 326 #include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" 327 #undef CV_REGISTER 328 #undef CV_REGISTERS_X86 329 330 default: 331 break; 332 } 333 } 334 return formatUnknownEnum(Id); 335 } 336 337 static std::string formatRegisterId(uint16_t Reg16, CPUType Cpu) { 338 return formatRegisterId(RegisterId(Reg16), Cpu); 339 } 340 341 static std::string formatRegisterId(ulittle16_t &Reg16, CPUType Cpu) { 342 return formatRegisterId(uint16_t(Reg16), Cpu); 343 } 344 345 static std::string formatRange(LocalVariableAddrRange Range) { 346 return formatv("[{0},+{1})", 347 formatSegmentOffset(Range.ISectStart, Range.OffsetStart), 348 Range.Range) 349 .str(); 350 } 351 352 static std::string formatGaps(uint32_t IndentLevel, 353 ArrayRef<LocalVariableAddrGap> Gaps) { 354 std::vector<std::string> GapStrs; 355 for (const auto &G : Gaps) { 356 GapStrs.push_back(formatv("({0},{1})", G.GapStartOffset, G.Range).str()); 357 } 358 return typesetItemList(GapStrs, 7, IndentLevel, ", "); 359 } 360 361 Error MinimalSymbolDumper::visitSymbolBegin(codeview::CVSymbol &Record) { 362 return visitSymbolBegin(Record, 0); 363 } 364 365 Error MinimalSymbolDumper::visitSymbolBegin(codeview::CVSymbol &Record, 366 uint32_t Offset) { 367 // formatLine puts the newline at the beginning, so we use formatLine here 368 // to start a new line, and then individual visit methods use format to 369 // append to the existing line. 370 P.formatLine("{0} | {1} [size = {2}]", 371 fmt_align(Offset, AlignStyle::Right, 6), 372 formatSymbolKind(Record.kind()), Record.length()); 373 P.Indent(); 374 return Error::success(); 375 } 376 377 Error MinimalSymbolDumper::visitSymbolEnd(CVSymbol &Record) { 378 if (RecordBytes) { 379 AutoIndent Indent(P, 7); 380 P.formatBinary("bytes", Record.content(), 0); 381 } 382 P.Unindent(); 383 return Error::success(); 384 } 385 386 std::string MinimalSymbolDumper::typeOrIdIndex(codeview::TypeIndex TI, 387 bool IsType) const { 388 if (TI.isSimple() || TI.isDecoratedItemId()) 389 return formatv("{0}", TI).str(); 390 auto &Container = IsType ? Types : Ids; 391 StringRef Name = Container.getTypeName(TI); 392 if (Name.size() > 32) { 393 Name = Name.take_front(32); 394 return std::string(formatv("{0} ({1}...)", TI, Name)); 395 } else 396 return std::string(formatv("{0} ({1})", TI, Name)); 397 } 398 399 std::string MinimalSymbolDumper::idIndex(codeview::TypeIndex TI) const { 400 return typeOrIdIndex(TI, false); 401 } 402 403 std::string MinimalSymbolDumper::typeIndex(TypeIndex TI) const { 404 return typeOrIdIndex(TI, true); 405 } 406 407 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, BlockSym &Block) { 408 P.format(" `{0}`", Block.Name); 409 AutoIndent Indent(P, 7); 410 P.formatLine("parent = {0}, end = {1}", Block.Parent, Block.End); 411 P.formatLine("code size = {0}, addr = {1}", Block.CodeSize, 412 formatSegmentOffset(Block.Segment, Block.CodeOffset)); 413 return Error::success(); 414 } 415 416 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, Thunk32Sym &Thunk) { 417 P.format(" `{0}`", Thunk.Name); 418 AutoIndent Indent(P, 7); 419 P.formatLine("parent = {0}, end = {1}, next = {2}", Thunk.Parent, Thunk.End, 420 Thunk.Next); 421 P.formatLine("kind = {0}, size = {1}, addr = {2}", 422 formatThunkOrdinal(Thunk.Thunk), Thunk.Length, 423 formatSegmentOffset(Thunk.Segment, Thunk.Offset)); 424 425 return Error::success(); 426 } 427 428 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 429 TrampolineSym &Tramp) { 430 AutoIndent Indent(P, 7); 431 P.formatLine("type = {0}, size = {1}, source = {2}, target = {3}", 432 formatTrampolineType(Tramp.Type), Tramp.Size, 433 formatSegmentOffset(Tramp.ThunkSection, Tramp.ThunkOffset), 434 formatSegmentOffset(Tramp.TargetSection, Tramp.ThunkOffset)); 435 436 return Error::success(); 437 } 438 439 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 440 SectionSym &Section) { 441 P.format(" `{0}`", Section.Name); 442 AutoIndent Indent(P, 7); 443 P.formatLine("length = {0}, alignment = {1}, rva = {2}, section # = {3}", 444 Section.Length, Section.Alignment, Section.Rva, 445 Section.SectionNumber); 446 P.printLine("characteristics ="); 447 AutoIndent Indent2(P, 2); 448 P.printLine(formatSectionCharacteristics(P.getIndentLevel(), 449 Section.Characteristics, 1, "", 450 CharacteristicStyle::Descriptive)); 451 return Error::success(); 452 } 453 454 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, CoffGroupSym &CG) { 455 P.format(" `{0}`", CG.Name); 456 AutoIndent Indent(P, 7); 457 P.formatLine("length = {0}, addr = {1}", CG.Size, 458 formatSegmentOffset(CG.Segment, CG.Offset)); 459 P.printLine("characteristics ="); 460 AutoIndent Indent2(P, 2); 461 P.printLine(formatSectionCharacteristics(P.getIndentLevel(), 462 CG.Characteristics, 1, "", 463 CharacteristicStyle::Descriptive)); 464 return Error::success(); 465 } 466 467 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 468 BPRelativeSym &BPRel) { 469 P.format(" `{0}`", BPRel.Name); 470 AutoIndent Indent(P, 7); 471 P.formatLine("type = {0}, offset = {1}", typeIndex(BPRel.Type), BPRel.Offset); 472 return Error::success(); 473 } 474 475 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 476 BuildInfoSym &BuildInfo) { 477 P.format(" BuildId = `{0}`", BuildInfo.BuildId); 478 return Error::success(); 479 } 480 481 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 482 CallSiteInfoSym &CSI) { 483 AutoIndent Indent(P, 7); 484 P.formatLine("type = {0}, addr = {1}", typeIndex(CSI.Type), 485 formatSegmentOffset(CSI.Segment, CSI.CodeOffset)); 486 return Error::success(); 487 } 488 489 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 490 EnvBlockSym &EnvBlock) { 491 AutoIndent Indent(P, 7); 492 for (const auto &Entry : EnvBlock.Fields) { 493 P.formatLine("- {0}", Entry); 494 } 495 return Error::success(); 496 } 497 498 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, FileStaticSym &FS) { 499 P.format(" `{0}`", FS.Name); 500 AutoIndent Indent(P, 7); 501 if (SymGroup) { 502 Expected<StringRef> FileName = 503 SymGroup->getNameFromStringTable(FS.ModFilenameOffset); 504 if (FileName) { 505 P.formatLine("type = {0}, file name = {1} ({2}), flags = {3}", 506 typeIndex(FS.Index), FS.ModFilenameOffset, *FileName, 507 formatLocalSymFlags(P.getIndentLevel() + 9, FS.Flags)); 508 } 509 return Error::success(); 510 } 511 512 P.formatLine("type = {0}, file name offset = {1}, flags = {2}", 513 typeIndex(FS.Index), FS.ModFilenameOffset, 514 formatLocalSymFlags(P.getIndentLevel() + 9, FS.Flags)); 515 return Error::success(); 516 } 517 518 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, ExportSym &Export) { 519 P.format(" `{0}`", Export.Name); 520 AutoIndent Indent(P, 7); 521 P.formatLine("ordinal = {0}, flags = {1}", Export.Ordinal, 522 formatExportFlags(P.getIndentLevel() + 9, Export.Flags)); 523 return Error::success(); 524 } 525 526 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 527 Compile2Sym &Compile2) { 528 AutoIndent Indent(P, 7); 529 SourceLanguage Lang = static_cast<SourceLanguage>( 530 Compile2.Flags & CompileSym2Flags::SourceLanguageMask); 531 CompilationCPU = Compile2.Machine; 532 P.formatLine("machine = {0}, ver = {1}, language = {2}", 533 formatMachineType(Compile2.Machine), Compile2.Version, 534 formatSourceLanguage(Lang)); 535 P.formatLine("frontend = {0}.{1}.{2}, backend = {3}.{4}.{5}", 536 Compile2.VersionFrontendMajor, Compile2.VersionFrontendMinor, 537 Compile2.VersionFrontendBuild, Compile2.VersionBackendMajor, 538 Compile2.VersionBackendMinor, Compile2.VersionBackendBuild); 539 P.formatLine("flags = {0}", 540 formatCompileSym2Flags(P.getIndentLevel() + 9, Compile2.Flags)); 541 P.formatLine( 542 "extra strings = {0}", 543 typesetStringList(P.getIndentLevel() + 9 + 2, Compile2.ExtraStrings)); 544 return Error::success(); 545 } 546 547 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 548 Compile3Sym &Compile3) { 549 AutoIndent Indent(P, 7); 550 SourceLanguage Lang = static_cast<SourceLanguage>( 551 Compile3.Flags & CompileSym3Flags::SourceLanguageMask); 552 CompilationCPU = Compile3.Machine; 553 P.formatLine("machine = {0}, Ver = {1}, language = {2}", 554 formatMachineType(Compile3.Machine), Compile3.Version, 555 formatSourceLanguage(Lang)); 556 P.formatLine("frontend = {0}.{1}.{2}.{3}, backend = {4}.{5}.{6}.{7}", 557 Compile3.VersionFrontendMajor, Compile3.VersionFrontendMinor, 558 Compile3.VersionFrontendBuild, Compile3.VersionFrontendQFE, 559 Compile3.VersionBackendMajor, Compile3.VersionBackendMinor, 560 Compile3.VersionBackendBuild, Compile3.VersionBackendQFE); 561 P.formatLine("flags = {0}", 562 formatCompileSym3Flags(P.getIndentLevel() + 9, Compile3.Flags)); 563 return Error::success(); 564 } 565 566 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 567 ConstantSym &Constant) { 568 P.format(" `{0}`", Constant.Name); 569 AutoIndent Indent(P, 7); 570 P.formatLine("type = {0}, value = {1}", typeIndex(Constant.Type), 571 toString(Constant.Value, 10)); 572 return Error::success(); 573 } 574 575 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, DataSym &Data) { 576 P.format(" `{0}`", Data.Name); 577 AutoIndent Indent(P, 7); 578 P.formatLine("type = {0}, addr = {1}", typeIndex(Data.Type), 579 formatSegmentOffset(Data.Segment, Data.DataOffset)); 580 return Error::success(); 581 } 582 583 Error MinimalSymbolDumper::visitKnownRecord( 584 CVSymbol &CVR, DefRangeFramePointerRelFullScopeSym &Def) { 585 P.format(" offset = {0}", Def.Offset); 586 return Error::success(); 587 } 588 589 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 590 DefRangeFramePointerRelSym &Def) { 591 AutoIndent Indent(P, 7); 592 P.formatLine("offset = {0}, range = {1}", Def.Hdr.Offset, 593 formatRange(Def.Range)); 594 P.formatLine("gaps = [{0}]", formatGaps(P.getIndentLevel() + 9, Def.Gaps)); 595 return Error::success(); 596 } 597 598 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 599 DefRangeRegisterRelSym &Def) { 600 AutoIndent Indent(P, 7); 601 P.formatLine("register = {0}, offset = {1}, offset in parent = {2}, has " 602 "spilled udt = {3}", 603 formatRegisterId(Def.Hdr.Register, CompilationCPU), 604 int32_t(Def.Hdr.BasePointerOffset), Def.offsetInParent(), 605 Def.hasSpilledUDTMember()); 606 P.formatLine("range = {0}, gaps = [{1}]", formatRange(Def.Range), 607 formatGaps(P.getIndentLevel() + 9, Def.Gaps)); 608 return Error::success(); 609 } 610 611 Error MinimalSymbolDumper::visitKnownRecord( 612 CVSymbol &CVR, DefRangeRegisterSym &DefRangeRegister) { 613 AutoIndent Indent(P, 7); 614 P.formatLine("register = {0}, may have no name = {1}, range start = " 615 "{2}, length = {3}", 616 formatRegisterId(DefRangeRegister.Hdr.Register, CompilationCPU), 617 bool(DefRangeRegister.Hdr.MayHaveNoName), 618 formatSegmentOffset(DefRangeRegister.Range.ISectStart, 619 DefRangeRegister.Range.OffsetStart), 620 DefRangeRegister.Range.Range); 621 P.formatLine("gaps = [{0}]", 622 formatGaps(P.getIndentLevel() + 9, DefRangeRegister.Gaps)); 623 return Error::success(); 624 } 625 626 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 627 DefRangeSubfieldRegisterSym &Def) { 628 AutoIndent Indent(P, 7); 629 bool NoName = !!(Def.Hdr.MayHaveNoName == 0); 630 P.formatLine("register = {0}, may have no name = {1}, offset in parent = {2}", 631 formatRegisterId(Def.Hdr.Register, CompilationCPU), NoName, 632 uint32_t(Def.Hdr.OffsetInParent)); 633 P.formatLine("range = {0}, gaps = [{1}]", formatRange(Def.Range), 634 formatGaps(P.getIndentLevel() + 9, Def.Gaps)); 635 return Error::success(); 636 } 637 638 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 639 DefRangeSubfieldSym &Def) { 640 AutoIndent Indent(P, 7); 641 P.formatLine("program = {0}, offset in parent = {1}, range = {2}", 642 Def.Program, Def.OffsetInParent, formatRange(Def.Range)); 643 P.formatLine("gaps = [{0}]", formatGaps(P.getIndentLevel() + 9, Def.Gaps)); 644 return Error::success(); 645 } 646 647 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, DefRangeSym &Def) { 648 AutoIndent Indent(P, 7); 649 P.formatLine("program = {0}, range = {1}", Def.Program, 650 formatRange(Def.Range)); 651 P.formatLine("gaps = [{0}]", formatGaps(P.getIndentLevel() + 9, Def.Gaps)); 652 return Error::success(); 653 } 654 655 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, FrameCookieSym &FC) { 656 AutoIndent Indent(P, 7); 657 P.formatLine("code offset = {0}, Register = {1}, kind = {2}, flags = {3}", 658 FC.CodeOffset, formatRegisterId(FC.Register, CompilationCPU), 659 formatCookieKind(FC.CookieKind), FC.Flags); 660 return Error::success(); 661 } 662 663 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, FrameProcSym &FP) { 664 AutoIndent Indent(P, 7); 665 P.formatLine("size = {0}, padding size = {1}, offset to padding = {2}", 666 FP.TotalFrameBytes, FP.PaddingFrameBytes, FP.OffsetToPadding); 667 P.formatLine("bytes of callee saved registers = {0}, exception handler addr " 668 "= {1}", 669 FP.BytesOfCalleeSavedRegisters, 670 formatSegmentOffset(FP.SectionIdOfExceptionHandler, 671 FP.OffsetOfExceptionHandler)); 672 P.formatLine( 673 "local fp reg = {0}, param fp reg = {1}", 674 formatRegisterId(FP.getLocalFramePtrReg(CompilationCPU), CompilationCPU), 675 formatRegisterId(FP.getParamFramePtrReg(CompilationCPU), CompilationCPU)); 676 P.formatLine("flags = {0}", 677 formatFrameProcedureOptions(P.getIndentLevel() + 9, FP.Flags)); 678 return Error::success(); 679 } 680 681 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 682 HeapAllocationSiteSym &HAS) { 683 AutoIndent Indent(P, 7); 684 P.formatLine("type = {0}, addr = {1} call size = {2}", typeIndex(HAS.Type), 685 formatSegmentOffset(HAS.Segment, HAS.CodeOffset), 686 HAS.CallInstructionSize); 687 return Error::success(); 688 } 689 690 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, InlineSiteSym &IS) { 691 AutoIndent Indent(P, 7); 692 P.formatLine("inlinee = {0}, parent = {1}, end = {2}", idIndex(IS.Inlinee), 693 IS.Parent, IS.End); 694 695 // Break down the annotation byte code and calculate code and line offsets. 696 // FIXME: It would be helpful if we could look up the initial file and inlinee 697 // lines offset using the inlinee index above. 698 uint32_t CodeOffset = 0; 699 int32_t LineOffset = 0; 700 for (auto &Annot : IS.annotations()) { 701 P.formatLine(" {0}", fmt_align(toHex(Annot.Bytes), AlignStyle::Left, 9)); 702 703 auto formatCodeOffset = [&](uint32_t Delta) { 704 CodeOffset += Delta; 705 P.format(" code 0x{0} (+0x{1})", utohexstr(CodeOffset), utohexstr(Delta)); 706 }; 707 auto formatCodeLength = [&](uint32_t Length) { 708 // Notably, changing the code length does not affect the code offset. 709 P.format(" code end 0x{0} (+0x{1})", utohexstr(CodeOffset + Length), 710 utohexstr(Length)); 711 }; 712 auto formatLineOffset = [&](int32_t Delta) { 713 LineOffset += Delta; 714 char Sign = Delta > 0 ? '+' : '-'; 715 P.format(" line {0} ({1}{2})", LineOffset, Sign, std::abs(Delta)); 716 }; 717 718 // Use the opcode to interpret the integer values. 719 switch (Annot.OpCode) { 720 case BinaryAnnotationsOpCode::Invalid: 721 break; 722 case BinaryAnnotationsOpCode::CodeOffset: 723 case BinaryAnnotationsOpCode::ChangeCodeOffset: 724 formatCodeOffset(Annot.U1); 725 break; 726 case BinaryAnnotationsOpCode::ChangeLineOffset: 727 formatLineOffset(Annot.S1); 728 break; 729 case BinaryAnnotationsOpCode::ChangeCodeLength: 730 formatCodeLength(Annot.U1); 731 // Apparently this annotation updates the code offset. It's hard to make 732 // MSVC produce this opcode, but clang uses it, and debuggers seem to use 733 // this interpretation. 734 CodeOffset += Annot.U1; 735 break; 736 case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: 737 formatCodeOffset(Annot.U1); 738 formatLineOffset(Annot.S1); 739 break; 740 case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: 741 formatCodeOffset(Annot.U2); 742 formatCodeLength(Annot.U1); 743 break; 744 745 case BinaryAnnotationsOpCode::ChangeFile: { 746 uint32_t FileOffset = Annot.U1; 747 StringRef Filename = "<unknown>"; 748 if (SymGroup) { 749 if (Expected<StringRef> MaybeFile = 750 SymGroup->getNameFromStringTable(FileOffset)) 751 Filename = *MaybeFile; 752 else 753 return MaybeFile.takeError(); 754 } 755 P.format(" setfile {0} 0x{1}", utohexstr(FileOffset)); 756 break; 757 } 758 759 // The rest of these are hard to convince MSVC to emit, so they are not as 760 // well understood. 761 case BinaryAnnotationsOpCode::ChangeCodeOffsetBase: 762 formatCodeOffset(Annot.U1); 763 break; 764 case BinaryAnnotationsOpCode::ChangeLineEndDelta: 765 case BinaryAnnotationsOpCode::ChangeRangeKind: 766 case BinaryAnnotationsOpCode::ChangeColumnStart: 767 case BinaryAnnotationsOpCode::ChangeColumnEnd: 768 P.format(" {0} {1}", Annot.Name, Annot.U1); 769 break; 770 case BinaryAnnotationsOpCode::ChangeColumnEndDelta: 771 P.format(" {0} {1}", Annot.Name, Annot.S1); 772 break; 773 } 774 } 775 return Error::success(); 776 } 777 778 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 779 RegisterSym &Register) { 780 P.format(" `{0}`", Register.Name); 781 AutoIndent Indent(P, 7); 782 P.formatLine("register = {0}, type = {1}", 783 formatRegisterId(Register.Register, CompilationCPU), 784 typeIndex(Register.Index)); 785 return Error::success(); 786 } 787 788 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 789 PublicSym32 &Public) { 790 P.format(" `{0}`", Public.Name); 791 AutoIndent Indent(P, 7); 792 P.formatLine("flags = {0}, addr = {1}", 793 formatPublicSymFlags(P.getIndentLevel() + 9, Public.Flags), 794 formatSegmentOffset(Public.Segment, Public.Offset)); 795 return Error::success(); 796 } 797 798 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, ProcRefSym &PR) { 799 P.format(" `{0}`", PR.Name); 800 AutoIndent Indent(P, 7); 801 P.formatLine("module = {0}, sum name = {1}, offset = {2}", PR.Module, 802 PR.SumName, PR.SymOffset); 803 return Error::success(); 804 } 805 806 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, LabelSym &Label) { 807 P.format(" `{0}` (addr = {1})", Label.Name, 808 formatSegmentOffset(Label.Segment, Label.CodeOffset)); 809 AutoIndent Indent(P, 7); 810 P.formatLine("flags = {0}", 811 formatProcSymFlags(P.getIndentLevel() + 9, Label.Flags)); 812 return Error::success(); 813 } 814 815 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, LocalSym &Local) { 816 P.format(" `{0}`", Local.Name); 817 AutoIndent Indent(P, 7); 818 819 std::string FlagStr = 820 formatLocalSymFlags(P.getIndentLevel() + 9, Local.Flags); 821 P.formatLine("type={0}, flags = {1}", typeIndex(Local.Type), FlagStr); 822 return Error::success(); 823 } 824 825 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 826 ObjNameSym &ObjName) { 827 P.format(" sig={0}, `{1}`", ObjName.Signature, ObjName.Name); 828 return Error::success(); 829 } 830 831 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, ProcSym &Proc) { 832 P.format(" `{0}`", Proc.Name); 833 AutoIndent Indent(P, 7); 834 P.formatLine("parent = {0}, end = {1}, addr = {2}, code size = {3}", 835 Proc.Parent, Proc.End, 836 formatSegmentOffset(Proc.Segment, Proc.CodeOffset), 837 Proc.CodeSize); 838 bool IsType = true; 839 switch (Proc.getKind()) { 840 case SymbolRecordKind::GlobalProcIdSym: 841 case SymbolRecordKind::ProcIdSym: 842 case SymbolRecordKind::DPCProcIdSym: 843 IsType = false; 844 break; 845 default: 846 break; 847 } 848 P.formatLine("type = `{0}`, debug start = {1}, debug end = {2}, flags = {3}", 849 typeOrIdIndex(Proc.FunctionType, IsType), Proc.DbgStart, 850 Proc.DbgEnd, 851 formatProcSymFlags(P.getIndentLevel() + 9, Proc.Flags)); 852 return Error::success(); 853 } 854 855 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 856 ScopeEndSym &ScopeEnd) { 857 return Error::success(); 858 } 859 860 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) { 861 AutoIndent Indent(P, 7); 862 for (const auto &I : Caller.Indices) { 863 P.formatLine("callee: {0}", idIndex(I)); 864 } 865 return Error::success(); 866 } 867 868 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 869 RegRelativeSym &RegRel) { 870 P.format(" `{0}`", RegRel.Name); 871 AutoIndent Indent(P, 7); 872 P.formatLine( 873 "type = {0}, register = {1}, offset = {2}", typeIndex(RegRel.Type), 874 formatRegisterId(RegRel.Register, CompilationCPU), RegRel.Offset); 875 return Error::success(); 876 } 877 878 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 879 ThreadLocalDataSym &Data) { 880 P.format(" `{0}`", Data.Name); 881 AutoIndent Indent(P, 7); 882 P.formatLine("type = {0}, addr = {1}", typeIndex(Data.Type), 883 formatSegmentOffset(Data.Segment, Data.DataOffset)); 884 return Error::success(); 885 } 886 887 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, UDTSym &UDT) { 888 P.format(" `{0}`", UDT.Name); 889 AutoIndent Indent(P, 7); 890 P.formatLine("original type = {0}", UDT.Type); 891 return Error::success(); 892 } 893 894 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 895 UsingNamespaceSym &UN) { 896 P.format(" `{0}`", UN.Name); 897 return Error::success(); 898 } 899 900 Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, 901 AnnotationSym &Annot) { 902 AutoIndent Indent(P, 7); 903 P.formatLine("addr = {0}", formatSegmentOffset(Annot.Segment, Annot.CodeOffset)); 904 P.formatLine("strings = {0}", typesetStringList(P.getIndentLevel() + 9 + 2, 905 Annot.Strings)); 906 return Error::success(); 907 } 908