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