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