Esempio n. 1
0
        private void Export(ILogger logger, Summary summary, DisassemblyResult disassemblyResult, BenchmarkCase benchmarkCase, ref int referenceIndex)
        {
            logger.WriteLine($"<h2>{summary[benchmarkCase].GetRuntimeInfo()}</h2>");
            logger.WriteLine("<table><tbody>");

            int methodIndex = 0;

            foreach (var method in disassemblyResult.Methods.Where(method => string.IsNullOrEmpty(method.Problem)))
            {
                referenceIndex++;
                logger.WriteLine($"<tr><th colspan=\"2\" style=\"text-align: left;\">{method.Name}</th><th></th></tr>");

                var pretty = DisassemblyPrettifier.Prettify(method, disassemblyResult, config, $"M{methodIndex++:00}");

                bool even = false, diffTheLabels = pretty.Count > 1;
                foreach (var element in pretty)
                {
                    if (element is DisassemblyPrettifier.Label label)
                    {
                        even = !even;

                        logger.WriteLine($"<tr class=\"{(even && diffTheLabels ? "evenMap" : string.Empty)}\">");
                        logger.WriteLine($"<td id=\"{referenceIndex}_{label.Id}\" class=\"label\" data-label=\"{referenceIndex}_{label.TextRepresentation}\"><pre><code>{label.TextRepresentation}</pre></code></td>");
                        logger.WriteLine("<td>&nbsp;</td></tr>");

                        continue;
                    }

                    logger.WriteLine($"<tr class=\"{(even && diffTheLabels ? "evenMap" : string.Empty)}\">");
                    logger.Write("<td></td>");

                    if (element is DisassemblyPrettifier.Reference reference)
                    {
                        logger.WriteLine($"<td id=\"{referenceIndex}\" class=\"reference\" data-reference=\"{referenceIndex}_{reference.Id}\"><a href=\"#{referenceIndex}_{reference.Id}\"><pre><code>{reference.TextRepresentation}</pre></code></a></td>");
                    }
                    else
                    {
                        logger.WriteLine($"<td><pre><code>{element.TextRepresentation}</pre></code></td>");
                    }

                    logger.Write("</tr>");
                }

                logger.WriteLine("<tr><td colspan=\"{2}\">&nbsp;</td></tr>");
            }

            foreach (var withProblems in disassemblyResult.Methods
                     .Where(method => !string.IsNullOrEmpty(method.Problem))
                     .GroupBy(method => method.Problem))
            {
                logger.WriteLine($"<tr><td colspan=\"{2}\"><b>{withProblems.Key}</b></td></tr>");
                foreach (var withProblem in withProblems)
                {
                    logger.WriteLine($"<tr><td colspan=\"{2}\">{withProblem.Name}</td></tr>");
                }
                logger.WriteLine("<tr><td colspan=\"{2}\"></td></tr>");
            }

            logger.WriteLine("</tbody></table>");
        }
            public bool TryDisassembleInstruction(ulong pc, byte[] data, uint flags, out DisassemblyResult result, int memoryOffset = 0)
            {
                var strBuf         = Marshal.AllocHGlobal(1024);
                var marshalledData = Marshal.AllocHGlobal(data.Length - memoryOffset);

                Marshal.Copy(data, memoryOffset, marshalledData, data.Length - memoryOffset);

                var bytes = llvm_disasm_instruction(context, marshalledData, (ulong)(data.Length - memoryOffset), strBuf, 1024);

                if (bytes == 0)
                {
                    result = default(DisassemblyResult);
                    return(false);
                }

                var strBldr = new StringBuilder();

                if (!HexFormatter(strBldr, bytes, memoryOffset, data))
                {
                    result = default(DisassemblyResult);
                    return(false);
                }

                result = new DisassemblyResult
                {
                    PC                = pc,
                    OpcodeSize        = bytes,
                    OpcodeString      = strBldr.ToString(),
                    DisassemblyString = Marshal.PtrToStringAnsi(strBuf)
                };

                Marshal.FreeHGlobal(strBuf);
                Marshal.FreeHGlobal(marshalledData);
                return(true);
            }
        public void CanParseInvalidMonoDisassemblyOutput()
        {
            const string input = @"lalala";

            var expected = new DisassemblyResult
            {
                Methods = new[]
                {
                    new DisassembledMethod
                    {
                        Name = "Foo",
                        Maps = new[]
                        {
                            new Map
                            {
                                Instructions = input
                                               .Split('\r', '\n')
                                               .Where(line => !string.IsNullOrWhiteSpace(line))
                                               .Select(line => new Diagnosers.Code {
                                    TextRepresentation = line
                                })
                                               .ToArray()
                            }
                        }
                    }
                },
                Errors = new[]
                {
                    @"It's impossible to find assembly instructions in the mono output"
                }
            };

            Check(input, expected, "Foo");
        }
        internal static void Export(ILogger logger, DisassemblyResult disassemblyResult, bool quotingCode = true)
        {
            int methodIndex = 0;

            foreach (var method in disassemblyResult.Methods.Where(method => string.IsNullOrEmpty(method.Problem)))
            {
                if (quotingCode)
                {
                    logger.WriteLine("```assembly");
                }

                logger.WriteLine($"; {method.Name}");

                var pretty = DisassemblyPrettifier.Prettify(method, $"M{methodIndex++:00}");

                uint totalSizeInBytes = 0;
                foreach (var element in pretty)
                {
                    if (element is DisassemblyPrettifier.Label label)
                    {
                        logger.WriteLine($"{label.TextRepresentation}:");

                        continue;
                    }
                    if (element.Source is Asm asm)
                    {
                        totalSizeInBytes += asm.SizeInBytes;
                    }

                    string prefix = "       ";
                    logger.WriteLine($"{prefix}{element.TextRepresentation.Replace("\n", "\n" + prefix)}");
                }

                logger.WriteLine($"; Total bytes of code {totalSizeInBytes}");
                if (quotingCode)
                {
                    logger.WriteLine("```");
                }
            }

            foreach (var withProblems in disassemblyResult.Methods
                     .Where(method => !string.IsNullOrEmpty(method.Problem))
                     .GroupBy(method => method.Problem))
            {
                logger.WriteLine($"**{withProblems.Key}**");
                foreach (var withProblem in withProblems)
                {
                    logger.WriteLine(withProblem.Name);
                }
            }

            logger.WriteLine();
        }
        public void CanParseMonoDisassemblyOutputFromWindowsWithoutTools()
        {
            const string input = @"
Basic block 0 starting at offset 0xd
Basic block 3 starting at offset 0xd
Basic block 5 starting at offset 0x18
Basic block 4 starting at offset 0x1c
Basic block 6 starting at offset 0x21
Basic block 1 starting at offset 0x24
CFA: [31] def_cfa: %rsp+0x8
Method int BenchmarkDotNet.Samples.Intro.IntroDisasm:Foo () emitted at 0000027E7E4E12E0 to 0000027E7E4E1312 (code length 50) [BenchmarkDotNet.Samples.dll]
'as' is not recognized as an internal or external command,
operable program or batch file.
'x86_64-w64-mingw32-objdump.exe' is not recognized as an internal or external command,
operable program or batch file.
";

            var expected = new DisassemblyResult
            {
                Methods = new[]
                {
                    new DisassembledMethod
                    {
                        Name = "Foo",
                        Maps = new[]
                        {
                            new Map
                            {
                                Instructions = input
                                               .Split('\r', '\n')
                                               .Where(line => !string.IsNullOrWhiteSpace(line))
                                               .Select(line => new Diagnosers.Code {
                                    TextRepresentation = line
                                })
                                               .ToArray()
                            }
                        }
                    }
                },
                Errors = new[]
                {
                    @"It's impossible to get Mono disasm because you don't have some required tools:
'as' is not recognized as an internal or external command
'x86_64-w64-mingw32-objdump.exe' is not recognized as an internal or external command"
                }
            };

            Check(input, expected, "Foo");
        }
        private static void Check(string input, DisassemblyResult expected, string methodName)
        {
            var disassemblyResult = MonoDisassembler.OutputParser.Parse(
                input.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None),
                methodName, commandLine: string.Empty);

            Assert.Equal(expected.Methods.Single().Name, disassemblyResult.Methods.Single().Name);
            Assert.Equal(expected.Methods[0].Maps[0].Instructions.Length, disassemblyResult.Methods[0].Maps[0].Instructions.Length);

            for (int i = 0; i < expected.Methods[0].Maps[0].Instructions.Length; i++)
            {
                Assert.Equal(expected.Methods[0].Maps[0].Instructions[i].TextRepresentation,
                             disassemblyResult.Methods[0].Maps[0].Instructions[i].TextRepresentation);
            }
        }
Esempio n. 7
0
        private string SaveDisassemblyResult(Summary summary, DisassemblyResult disassemblyResult)
        {
            string filePath = $"{Path.Combine(summary.ResultsDirectoryPath, Guid.NewGuid().ToString())}-diff.temp";

            if (File.Exists(filePath))
            {
                File.Delete(filePath);
            }

            using (var stream = new StreamWriter(filePath, append: false))
            {
                using (var streamLogger = new StreamLogger(stream))
                {
                    GithubMarkdownDisassemblyExporter.Export(streamLogger, disassemblyResult, config, quotingCode: false);
                }
            }

            return(filePath);
        }
Esempio n. 8
0
        private static string Export(Summary summary, BenchmarkCase benchmarkCase, DisassemblyResult disassemblyResult, PmcStats pmcStats)
        {
            string filePath = $"{Path.Combine(summary.ResultsDirectoryPath, benchmarkCase.Descriptor.WorkloadMethod.Name)}-{benchmarkCase.Job.Environment.Jit}-{benchmarkCase.Job.Environment.Platform}-instructionPointer.html";

            if (File.Exists(filePath))
            {
                File.Delete(filePath);
            }

            var totals    = SumHardwareCountersStatsOfBenchmarkedCode(disassemblyResult, pmcStats);
            var perMethod = SumHardwareCountersPerMethod(disassemblyResult, pmcStats);

            using (var stream = StreamWriter.FromPath(filePath))
            {
                Export(new StreamLogger(stream), benchmarkCase, totals, perMethod, pmcStats.Counters.Keys.ToArray());
            }

            return(filePath);
        }
        private bool TryDisassembleRiscVInstruction(ulong pc, byte[] memory, uint flags, out DisassemblyResult result, int memoryOffset = 0)
        {
            var opcode = BitHelper.ToUInt32(memory, memoryOffset, Math.Min(4, memory.Length - memoryOffset), true);

            if (!TryDecodeRiscVOpcodeLength(opcode, out var opcodeLength))
            {
                result = default(DisassemblyResult);
                return(false);
            }

            // trim opcode and keep only `opcodeLength` LSBytes
            opcode &= uint.MaxValue >> (64 - (opcodeLength * 8));

            result = new DisassemblyResult()
            {
                PC           = pc,
                OpcodeSize   = opcodeLength,
                OpcodeString = opcode.ToString("x").PadLeft(opcodeLength, '0')
            };
            return(true);
        }
        private static void Check(string input, DisassemblyResult expected, string methodName)
        {
            var disassemblyResult = MonoDisassembler.OutputParser.Parse(
                input.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None),
                methodName, commandLine: string.Empty);

            Assert.Equal(expected.Methods.Single().Name, disassemblyResult.Methods.Single().Name);
            Assert.Equal(expected.Methods[0].Maps[0].SourceCodes.Length, disassemblyResult.Methods[0].Maps[0].SourceCodes.Length);

            for (int i = 0; i < expected.Methods[0].Maps[0].SourceCodes.Length; i++)
            {
                Assert.Equal(((MonoCode)expected.Methods[0].Maps[0].SourceCodes[i]).Text,
                             ((MonoCode)disassemblyResult.Methods[0].Maps[0].SourceCodes[i]).Text);
            }

            Assert.Equal(expected.Errors.Length, disassemblyResult.Errors.Length);
            for (int i = 0; i < expected.Errors.Length; i++)
            {
                Assert.Equal(expected.Errors[i].Replace("\r", "").Replace("\n", ""), disassemblyResult.Errors[i].Replace("\r", "").Replace("\n", ""));
            }
        }
        private string Export(Summary summary, Benchmark benchmark, DisassemblyResult disassemblyResult, PmcStats pmcStats)
        {
            var filePath = $"{Path.Combine(summary.ResultsDirectoryPath, benchmark.Target.Method.Name)}-{benchmark.Job.Env.Jit}-{benchmark.Job.Env.Platform}-instructionPointer.html";

            if (File.Exists(filePath))
            {
                File.Delete(filePath);
            }

            checked
            {
                var totals    = SumHardwareCountersStatsOfBenchmarkedCode(disassemblyResult, pmcStats);
                var perMethod = SumHardwareCountersPerMethod(disassemblyResult, pmcStats);

                using (var stream = Portability.StreamWriter.FromPath(filePath))
                {
                    Export(new StreamLogger(stream), benchmark, totals, perMethod, pmcStats.Counters.Keys.ToArray());
                }
            }

            return(filePath);
        }
        private string Export(Summary summary, BenchmarkCase benchmarkCase, DisassemblyResult disassemblyResult, PmcStats pmcStats)
        {
            string filePath = Path.Combine(summary.ResultsDirectoryPath,
                                           $"{FolderNameHelper.ToFolderName(benchmarkCase.Descriptor.Type)}." +
                                           $"{benchmarkCase.Descriptor.WorkloadMethod.Name}." +
                                           $"{GetShortRuntimeInfo(summary[benchmarkCase].GetRuntimeInfo())}.counters.html");

            filePath.DeleteFileIfExists();

            var totals    = SumHardwareCountersStatsOfBenchmarkedCode(disassemblyResult, pmcStats);
            var perMethod = SumHardwareCountersPerMethod(disassemblyResult, pmcStats);

            using (var stream = new StreamWriter(filePath, append: false))
            {
                using (var streamLogger = new StreamLogger(stream))
                {
                    Export(streamLogger, benchmarkCase, totals, perMethod, pmcStats.Counters.Keys.ToArray());
                }
            }

            return(filePath);
        }
Esempio n. 13
0
        internal static string BuildDisassemblyString(DisassemblyResult disassemblyResult, DisassemblyDiagnoserConfig config)
        {
            StringBuilder sb = new StringBuilder();

            int methodIndex = 0;

            foreach (var method in disassemblyResult.Methods.Where(method => string.IsNullOrEmpty(method.Problem)))
            {
                sb.AppendLine("```assembly");

                sb.AppendLine($"; {method.Name}");

                var pretty = Prettify.Value.Invoke(method, disassemblyResult, config, $"M{methodIndex++:00}");

                ulong totalSizeInBytes = 0;
                foreach (var element in pretty)
                {
                    if (element.Source() is Asm asm)
                    {
                        checked
                        {
                            totalSizeInBytes += (uint)asm.Instruction.ByteLength;
                        }

                        sb.AppendLine($"       {element.TextRepresentation()}");
                    }
                    else // it's a DisassemblyPrettifier.Label (internal type..)
                    {
                        sb.AppendLine($"{element.TextRepresentation()}:");
                    }
                }

                sb.AppendLine($"; Total bytes of code {totalSizeInBytes}");
                sb.AppendLine("```");
            }

            return(sb.ToString());
        }
        /// <summary>
        /// there might be some hardware counter events not belonging to the benchmarked code (for example CLR or BenchmarkDotNet's Engine)
        /// to calculate the % per IP we need to know the total per benchmark, not per process
        /// </summary>
        private static Dictionary <HardwareCounter, (ulong withoutNoise, ulong total)> SumHardwareCountersStatsOfBenchmarkedCode(
            DisassemblyResult disassemblyResult, PmcStats pmcStats)
        {
            IEnumerable <ulong> Range(Asm asm)
            {
                // most probably asm.StartAddress would be enough, but I don't want to miss any edge case
                for (ulong instructionPointer = asm.StartAddress; instructionPointer < asm.EndAddress; instructionPointer++)
                {
                    yield return(instructionPointer);
                }
            }

            var instructionPointers = new HashSet <ulong>(
                disassemblyResult
                .Methods
                .SelectMany(method => method.Maps)
                .SelectMany(map => map.Instructions)
                .OfType <Asm>()
                .SelectMany(Range)
                .Distinct());

            return(pmcStats.Counters.ToDictionary(data => data.Key, data =>
            {
                ulong withoutNoise = 0, total = 0;

                foreach (var ipToCount in data.Value.PerInstructionPointer)
                {
                    total += ipToCount.Value;

                    if (instructionPointers.Contains(ipToCount.Key))
                    {
                        withoutNoise += ipToCount.Value;
                    }
                }

                return (withoutNoise, total);
            }));
        }
            public bool TryDisassembleInstruction(ulong pc, byte[] memory, uint flags, out DisassemblyResult result, int memoryOffset = 0)
            {
                switch (pc)
                {
                case 0xFFFFFFF0:
                case 0xFFFFFFF1:
                    // Return to Handler mode, exception return uses non-floating-point state from the MSP and execution uses MSP after return.
                    result = new DisassemblyResult
                    {
                        PC                = pc,
                        OpcodeSize        = 4,
                        OpcodeString      = pc.ToString("X"),
                        DisassemblyString = "Handler mode: non-floating-point state, MSP/MSP"
                    };
                    return(true);

                case 0xFFFFFFF8:
                case 0xFFFFFFF9:
                    // Return to Thread mode, exception return uses non-floating-point state from the MSP and execution uses MSP after return.
                    result = new DisassemblyResult
                    {
                        PC                = pc,
                        OpcodeSize        = 4,
                        OpcodeString      = pc.ToString("X"),
                        DisassemblyString = "Thread mode: non-floating-point state, MSP/MSP"
                    };
                    return(true);

                case 0xFFFFFFFC:
                case 0xFFFFFFFD:
                    // Return to Thread mode, exception return uses non-floating-point state from the PSP and execution uses PSP after return.
                    result = new DisassemblyResult
                    {
                        PC                = pc,
                        OpcodeSize        = 4,
                        OpcodeString      = pc.ToString("X"),
                        DisassemblyString = "Thread mode: non-floating-point state, PSP/PSP"
                    };
                    return(true);

                case 0xFFFFFFE0:
                case 0xFFFFFFE1:
                    // Return to Handler mode, exception return uses floating-point state from the MSP and execution uses MSP after return.
                    result = new DisassemblyResult
                    {
                        PC                = pc,
                        OpcodeSize        = 4,
                        OpcodeString      = pc.ToString("X"),
                        DisassemblyString = "Handler mode: floating-point state, MSP/MSP"
                    };
                    return(true);

                case 0xFFFFFFE8:
                case 0xFFFFFFE9:
                    // Return to Thread mode, exception return uses floating-point state from the MSP and execution uses MSP after return.
                    result = new DisassemblyResult
                    {
                        PC                = pc,
                        OpcodeSize        = 4,
                        OpcodeString      = pc.ToString("X"),
                        DisassemblyString = "Thread mode: floating-point state, MSP/MSP"
                    };
                    return(true);

                case 0xFFFFFFEC:
                case 0xFFFFFFED:
                    // Return to Thread mode, exception return uses floating-point state from the PSP and execution uses PSP after return.
                    result = new DisassemblyResult
                    {
                        PC                = pc,
                        OpcodeSize        = 4,
                        OpcodeString      = pc.ToString("X"),
                        DisassemblyString = "Thread mode: floating-point state, PSP/PSP"
                    };
                    return(true);

                default:
                    return(underlyingDisassembler.TryDisassembleInstruction(pc, memory, flags, out result, memoryOffset));
                }
            }
        public void CanParseMonoDisassemblyOutputFromMac()
        {
            const string input = @"
CFA: [0] def_cfa: %rsp+0x8
CFA: [0] offset: unknown at cfa-0x8
CFA: [4] def_cfa_offset: 0x10
CFA: [8] offset: %r15 at cfa-0x10
Basic block 0 starting at offset 0xb
Basic block 2 starting at offset 0xb
Basic block 1 starting at offset 0x27
CFA: [2f] def_cfa: %rsp+0x8
Method void BenchmarkDotNet.Samples.CPU.Cpu_Atomics:NoLock () emitted at 0x1027cdf80 to 0x1027cdfb0 (code length 48) [BenchmarkDotNet.Samples.exe]
/var/folders/ld/p9yn04fs3ys6h_dkyxvv95_40000gn/T/.WuSVhL:
(__TEXT,__text) section
chmarkDotNet_Samples_CPU_Cpu_Atomics_NoLock:
0000000000000000	subq	$0x8, %rsp
0000000000000004	movq	%r15, (%rsp)
0000000000000008	movq	%rdi, %r15
000000000000000b	movslq	0x18(%r15), %rax
000000000000000f	incl	%eax
0000000000000011	movl	%eax, 0x18(%r15)
0000000000000015	incl	%eax
0000000000000017	movl	%eax, 0x18(%r15)
000000000000001b	incl	%eax
000000000000001d	movl	%eax, 0x18(%r15)
0000000000000021	incl	%eax
0000000000000023	movl	%eax, 0x18(%r15)
0000000000000027	movq	(%rsp), %r15
000000000000002b	addq	$0x8, %rsp
000000000000002f	retq"    ;

            var expected = new DisassemblyResult()
            {
                Methods = new[]
                {
                    new DisassembledMethod()
                    {
                        Name = "NoLock",
                        Maps = new[]
                        {
                            new Map()
                            {
                                Instructions = new[]
                                {
                                    new Diagnosers.Code {
                                        TextRepresentation = "subq\t$0x8, %rsp"
                                    },

                                    new Diagnosers.Code {
                                        TextRepresentation = "movq\t%r15, (%rsp)"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "movq\t%rdi, %r15"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "movslq\t0x18(%r15), %rax"
                                    },

                                    new Diagnosers.Code {
                                        TextRepresentation = "incl\t%eax"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "movl\t%eax, 0x18(%r15)"
                                    },

                                    new Diagnosers.Code {
                                        TextRepresentation = "incl\t%eax"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "movl\t%eax, 0x18(%r15)"
                                    },

                                    new Diagnosers.Code {
                                        TextRepresentation = "incl\t%eax"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "movl\t%eax, 0x18(%r15)"
                                    },

                                    new Diagnosers.Code {
                                        TextRepresentation = "incl\t%eax"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "movl\t%eax, 0x18(%r15)"
                                    },

                                    new Diagnosers.Code {
                                        TextRepresentation = "movq\t(%rsp), %r15"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "addq\t$0x8, %rsp"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "retq"
                                    }
                                }
                            }
                        }
                    }
                }
            };

            Check(input, expected, "NoLock");
        }
        private static IReadOnlyList <MethodWithCounters> SumHardwareCountersPerMethod(DisassemblyResult disassemblyResult, PmcStats pmcStats)
        {
            var model = new List <MethodWithCounters>(disassemblyResult.Methods.Length);

            foreach (var method in disassemblyResult.Methods.Where(method => string.IsNullOrEmpty(method.Problem)))
            {
                var groups = new List <List <CodeWithCounters> >();

                foreach (var map in method.Maps)
                {
                    var codeWithCounters = new List <CodeWithCounters>(map.Instructions.Length);

                    foreach (var instruction in map.Instructions)
                    {
                        var totalsPerCounter = pmcStats.Counters.Keys.ToDictionary(key => key, _ => default(ulong));

                        if (instruction is Asm asm)
                        {
                            foreach (var hardwareCounter in pmcStats.Counters)
                            {
                                // most probably asm.StartAddress would be enough, but I don't want to miss any edge case
                                for (ulong instructionPointer = asm.StartAddress; instructionPointer < asm.EndAddress; instructionPointer++)
                                {
                                    if (hardwareCounter.Value.PerInstructionPointer.TryGetValue(instructionPointer, out ulong value))
                                    {
                                        totalsPerCounter[hardwareCounter.Key] = totalsPerCounter[hardwareCounter.Key] + value;
                                    }
                                }
                            }
                        }

                        codeWithCounters.Add(new CodeWithCounters
                        {
                            Code          = instruction,
                            SumPerCounter = totalsPerCounter
                        });
                    }

                    groups.Add(codeWithCounters);
                }

                model.Add(new MethodWithCounters
                {
                    Method        = method,
                    Instructions  = groups,
                    SumPerCounter = pmcStats.Counters.Keys.ToDictionary(
                        hardwareCounter => hardwareCounter,
                        hardwareCounter =>
                    {
                        ulong sum = 0;

                        foreach (var group in groups)
                        {
                            foreach (var codeWithCounter in group)
                            {
                                sum += codeWithCounter.SumPerCounter[hardwareCounter];
                            }
                        }

                        return(sum);
                    }
                        )
                });
            }

            return(model);
        }
        public void CanParseMonoDisassemblyOutput()
        {
            const string input = @"
LOCAL REGALLOC BLOCK 2:
	1  il_seq_point il: 0x0
	2  loadi4_membase R11 <- [%edi + 0xc]
	3  int_add_imm R13 <- R11 [1] clobbers: 1
	4  storei4_membase_reg [%edi + 0xc] <- R13
	5  il_seq_point il: 0xe
	6  move R16 <- R13
	7  int_add_imm R18 <- R16 [1] clobbers: 1
	8  storei4_membase_reg [%edi + 0xc] <- R18
	9  il_seq_point il: 0x1c
	10 move R21 <- R18
	11 int_add_imm R23 <- R21 [1] clobbers: 1
	12 storei4_membase_reg [%edi + 0xc] <- R23
	13 il_seq_point il: 0x2a
	14 move R26 <- R23
	15 int_add_imm R28 <- R26 [1] clobbers: 1
	16 storei4_membase_reg [%edi + 0xc] <- R28
	17 il_seq_point il: 0x38
liveness: %edi [4 - 0]
liveness: R11 [2 - 2]
liveness: R13 [3 - 3]
liveness: R16 [6 - 6]
liveness: R18 [7 - 7]
liveness: R21 [10 - 10]
liveness: R23 [11 - 11]
liveness: R26 [14 - 14]
liveness: R28 [15 - 15]
processing:	17 il_seq_point il: 0x38
	17 il_seq_point il: 0x38
processing:	16 storei4_membase_reg [%edi + 0xc] <- R28
	assigned sreg1 %eax to R28
	16 storei4_membase_reg [%edi + 0xc] <- %eax
processing:	15 int_add_imm R28 <- R26 [1] clobbers: 1
	assigned dreg %eax to dest R28
	freeable %eax (R28) (born in 15)
	assigned sreg1 %eax to R26
	15 int_add_imm %eax <- %eax [1] clobbers: 1
processing:	14 move R26 <- R23
	assigned dreg %eax to dest R26
	freeable %eax (R26) (born in 14)
	assigned sreg1 %eax to R23
	14 move %eax <- %eax
processing:	13 il_seq_point il: 0x2a
	13 il_seq_point il: 0x2a
processing:	12 storei4_membase_reg [%edi + 0xc] <- R23
	12 storei4_membase_reg [%edi + 0xc] <- %eax
processing:	11 int_add_imm R23 <- R21 [1] clobbers: 1
	assigned dreg %eax to dest R23
	freeable %eax (R23) (born in 11)
	assigned sreg1 %eax to R21
	11 int_add_imm %eax <- %eax [1] clobbers: 1
processing:	10 move R21 <- R18
	assigned dreg %eax to dest R21
	freeable %eax (R21) (born in 10)
	assigned sreg1 %eax to R18
	10 move %eax <- %eax
processing:	9  il_seq_point il: 0x1c
	9  il_seq_point il: 0x1c
processing:	8  storei4_membase_reg [%edi + 0xc] <- R18
	8  storei4_membase_reg [%edi + 0xc] <- %eax
processing:	7  int_add_imm R18 <- R16 [1] clobbers: 1
	assigned dreg %eax to dest R18
	freeable %eax (R18) (born in 7)
	assigned sreg1 %eax to R16
	7  int_add_imm %eax <- %eax [1] clobbers: 1
processing:	6  move R16 <- R13
	assigned dreg %eax to dest R16
	freeable %eax (R16) (born in 6)
	assigned sreg1 %eax to R13
	6  move %eax <- %eax
processing:	5  il_seq_point il: 0xe
	5  il_seq_point il: 0xe
processing:	4  storei4_membase_reg [%edi + 0xc] <- R13
	4  storei4_membase_reg [%edi + 0xc] <- %eax
processing:	3  int_add_imm R13 <- R11 [1] clobbers: 1
	assigned dreg %eax to dest R13
	freeable %eax (R13) (born in 3)
	assigned sreg1 %eax to R11
	3  int_add_imm %eax <- %eax [1] clobbers: 1
processing:	2  loadi4_membase R11 <- [%edi + 0xc]
	assigned dreg %eax to dest R11
	freeable %eax (R11) (born in 2)
	2  loadi4_membase %eax <- [%edi + 0xc]
processing:	1  il_seq_point il: 0x0
	1  il_seq_point il: 0x0
CFA: [0] def_cfa: %esp+0x4
CFA: [0] offset: unknown at cfa-0x4
CFA: [1] def_cfa_offset: 0x8
CFA: [1] offset: %ebp at cfa-0x8
CFA: [3] def_cfa_reg: %ebp
CFA: [4] offset: %edi at cfa-0xc
Argument 0 assigned to register %edi
Basic block 0 starting at offset 0xa
Basic block 2 starting at offset 0xa
Basic block 1 starting at offset 0x1d
Method void BenchmarkDotNet.Samples.CPU.Cpu_Atomics:NoLock () emitted at 03AC11D0 to 03AC11F6 (code length 38) [BenchmarkDotNet.Samples.exe]
";

            var expected = new DisassemblyResult()
            {
                Methods = new[]
                {
                    new DisassembledMethod()
                    {
                        Name = "NoLock",
                        Maps = new Map[]
                        {
                            new Map()
                            {
                                Instructions = new[]
                                {
                                    new Diagnosers.Code {
                                        TextRepresentation = "loadi4_membase %eax <- [%edi + 0xc]"
                                    },

                                    new Diagnosers.Code {
                                        TextRepresentation = "int_add_imm %eax <- %eax [1] clobbers: 1"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "storei4_membase_reg [%edi + 0xc] <- %eax"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "move %eax <- %eax"
                                    },

                                    new Diagnosers.Code {
                                        TextRepresentation = "int_add_imm %eax <- %eax [1] clobbers: 1"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "storei4_membase_reg [%edi + 0xc] <- %eax"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "move %eax <- %eax"
                                    },

                                    new Diagnosers.Code {
                                        TextRepresentation = "int_add_imm %eax <- %eax [1] clobbers: 1"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "storei4_membase_reg [%edi + 0xc] <- %eax"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "move %eax <- %eax"
                                    },

                                    new Diagnosers.Code {
                                        TextRepresentation = "int_add_imm %eax <- %eax [1] clobbers: 1"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "storei4_membase_reg [%edi + 0xc] <- %eax"
                                    },
                                }
                            }
                        }
                    }
                }
            };

            var disassemblyResult = MonoDisassembler.OutputParser.Parse(
                input.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None),
                "BenchmarkDotNet.Samples.CPU.Cpu_Atomics:NoLock",
                "NoLock");

            Assert.Equal(expected.Methods.Single().Name, disassemblyResult.Methods.Single().Name);
            Assert.Equal(expected.Methods[0].Maps[0].Instructions.Length, disassemblyResult.Methods[0].Maps[0].Instructions.Length);

            for (int i = 0; i < expected.Methods[0].Maps[0].Instructions.Length; i++)
            {
                Assert.Equal(expected.Methods[0].Maps[0].Instructions[i].TextRepresentation,
                             disassemblyResult.Methods[0].Maps[0].Instructions[i].TextRepresentation);
            }
        }
        public void CanParseMonoDisassemblyOutputFromWindows()
        {
            const string input = @"
CFA: [0] def_cfa: %rsp+0x8
CFA: [0] offset: unknown at cfa-0x8
CFA: [4] def_cfa_offset: 0x30
CFA: [8] offset: %rsi at cfa-0x30
CFA: [d] offset: %r14 at cfa-0x28
CFA: [12] offset: %r15 at cfa-0x20
Basic block 0 starting at offset 0x12
Basic block 3 starting at offset 0x12
Basic block 5 starting at offset 0x20
Basic block 4 starting at offset 0x37
Basic block 6 starting at offset 0x4a
Basic block 1 starting at offset 0x52
CFA: [64] def_cfa: %rsp+0x8
Method int BenchmarkDotNet.Samples.My:NoLock () emitted at 000001D748E912E0 to 000001D748E91345 (code length 101) [BenchmarkDotNet.Samples.dll]

/test.o:     file format pe-x86-64


Disassembly of section .text:

0000000000000000 <chmarkDotNet_Samples_My_NoLock>:
   0:	48 83 ec 28             sub    $0x28,%rsp
   4:	48 89 34 24             mov    %rsi,(%rsp)
   8:	4c 89 74 24 08          mov    %r14,0x8(%rsp)
   d:	4c 89 7c 24 10          mov    %r15,0x10(%rsp)
  12:	45 33 ff                xor    %r15d,%r15d
  15:	45 33 f6                xor    %r14d,%r14d
  18:	eb 1d                   jmp    37 <chmarkDotNet_Samples_My_NoLock+0x37>
  1a:	48 8d 64 24 00          lea    0x0(%rsp),%rsp
  1f:	90                      nop
  20:	49 8b c7                mov    %r15,%rax
  23:	49 8b ce                mov    %r14,%rcx
  26:	ba 02 00 00 00          mov    $0x2,%edx
  2b:	0f af ca                imul   %edx,%ecx
  2e:	4c 8b f8                mov    %rax,%r15
  31:	44 03 f9                add    %ecx,%r15d
  34:	41 ff c6                inc    %r14d
  37:	41 83 fe 0d             cmp    $0xd,%r14d
  3b:	40 0f 9c c6             setl   %sil
  3f:	48 0f b6 f6             movzbq %sil,%rsi
  43:	48 8b c6                mov    %rsi,%rax
  46:	85 c0                   test   %eax,%eax
  48:	75 d6                   jne    20 <chmarkDotNet_Samples_My_NoLock+0x20>
  4a:	44 89 7c 24 18          mov    %r15d,0x18(%rsp)
  4f:	49 8b c7                mov    %r15,%rax
  52:	48 8b 34 24             mov    (%rsp),%rsi
  56:	4c 8b 74 24 08          mov    0x8(%rsp),%r14
  5b:	4c 8b 7c 24 10          mov    0x10(%rsp),%r15
  60:	48 83 c4 28             add    $0x28,%rsp
  64:	c3                      retq
  65:   90                      nop
  66:   90                      nop
";

            var expected = new DisassemblyResult()
            {
                Methods = new[]
                {
                    new DisassembledMethod()
                    {
                        Name = "NoLock",
                        Maps = new[]
                        {
                            new Map()
                            {
                                Instructions = new[]
                                {
                                    new Diagnosers.Code {
                                        TextRepresentation = "sub    $0x28,%rsp"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "mov    %rsi,(%rsp)"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "mov    %r14,0x8(%rsp)"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "mov    %r15,0x10(%rsp)"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "xor    %r15d,%r15d"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "xor    %r14d,%r14d"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "jmp    37 <chmarkDotNet_Samples_My_NoLock+0x37>"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "lea    0x0(%rsp),%rsp"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "nop"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "mov    %r15,%rax"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "mov    %r14,%rcx"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "mov    $0x2,%edx"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "imul   %edx,%ecx"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "mov    %rax,%r15"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "add    %ecx,%r15d"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "inc    %r14d"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "cmp    $0xd,%r14d"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "setl   %sil"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "movzbq %sil,%rsi"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "mov    %rsi,%rax"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "test   %eax,%eax"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "jne    20 <chmarkDotNet_Samples_My_NoLock+0x20>"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "mov    %r15d,0x18(%rsp)"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "mov    %r15,%rax"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "mov    (%rsp),%rsi"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "mov    0x8(%rsp),%r14"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "mov    0x10(%rsp),%r15"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "add    $0x28,%rsp"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "retq"
                                    },
                                }
                            }
                        }
                    }
                }
            };

            Check(input, expected, "NoLock");
        }
Esempio n. 20
0
        internal static void Export(ILogger logger, DisassemblyResult disassemblyResult, DisassemblyDiagnoserConfig config, bool quotingCode = true)
        {
            int methodIndex = 0;

            foreach (var method in disassemblyResult.Methods.Where(method => string.IsNullOrEmpty(method.Problem)))
            {
                if (quotingCode)
                {
                    logger.WriteLine("```assembly");
                }

                logger.WriteLine($"; {method.Name}");

                var pretty = DisassemblyPrettifier.Prettify(method, disassemblyResult, config, $"M{methodIndex++:00}");

                ulong totalSizeInBytes = 0;
                foreach (var element in pretty)
                {
                    if (element is DisassemblyPrettifier.Label label)
                    {
                        logger.WriteLine($"{label.TextRepresentation}:");
                    }
                    else if (element.Source is Sharp sharp)
                    {
                        logger.WriteLine($"; {sharp.Text.Replace("\n", "\n; ")}"); // they are multiline and we need to add ; for each line
                    }
                    else if (element.Source is Asm asm)
                    {
                        checked
                        {
                            totalSizeInBytes += (uint)asm.Instruction.ByteLength;
                        }

                        logger.WriteLine($"       {element.TextRepresentation}");
                    }
                    else if (element.Source is MonoCode mono)
                    {
                        logger.WriteLine(mono.Text);
                    }
                }

                logger.WriteLine($"; Total bytes of code {totalSizeInBytes}");
                if (quotingCode)
                {
                    logger.WriteLine("```");
                }
            }

            foreach (var withProblems in disassemblyResult.Methods
                     .Where(method => !string.IsNullOrEmpty(method.Problem))
                     .GroupBy(method => method.Problem))
            {
                logger.WriteLine($"**{withProblems.Key}**");
                foreach (var withProblem in withProblems)
                {
                    logger.WriteLine(withProblem.Name);
                }
            }

            logger.WriteLine();
        }
        private void Export(ILogger logger, DisassemblyResult disassemblyResult, Benchmark benchmark)
        {
            logger.WriteLine("<!DOCTYPE html><html lang='en'><head><meta charset='utf-8' />");
            logger.WriteLine($"<title>Output of DisassemblyDiagnoser for {benchmark.DisplayInfo}</title>");
            logger.WriteLine(InstructionPointerExporter.CssStyle);
            logger.WriteLine("</head>");
            logger.WriteLine("<body>");

            logger.WriteLine("<table>");
            logger.WriteLine("<tbody>");

            var methodNameToNativeCode = disassemblyResult.Methods
                .Where(method => string.IsNullOrEmpty(method.Problem))
                .ToDictionary(method => method.Name, method => method.NativeCode);

            foreach (var method in disassemblyResult.Methods.Where(method => string.IsNullOrEmpty(method.Problem)))
            {
                // I am using NativeCode as the id to avoid any problems with special characters like <> in html ;)
                logger.WriteLine(
                    $"<tr><th colspan=\"2\" id=\"{method.NativeCode}\" style=\"text-align: left;\">{FormatMethodAddress(method.NativeCode)} {method.Name}</th><th></th></tr>");

                // there is no need to distinguish the maps visually if there is only one type of code
                var diffTheMaps = method.Maps.SelectMany(map => map.Instructions).Select(ins => ins.GetType()).Distinct().Count() > 1; 

                bool evenMap = true;
                foreach (var map in method.Maps)
                {
                    foreach (var instruction in map.Instructions)
                    {
                        logger.WriteLine($"<tr class=\"{(evenMap && diffTheMaps ? "evenMap" : string.Empty)}\">");
                        logger.WriteLine($"<td><pre><code>{instruction.TextRepresentation}</pre></code></td>");

                        if (!string.IsNullOrEmpty(instruction.Comment) && methodNameToNativeCode.TryGetValue(instruction.Comment, out var id))
                        {
                            logger.WriteLine($"<td><a href=\"#{id}\">{GetShortName(instruction.Comment)}</a></td>");
                        }
                        else
                        {
                            logger.WriteLine($"<td>{instruction.Comment}</td>");
                        }

                        logger.WriteLine("</tr>");
                    }

                    evenMap = !evenMap;
                }

                logger.WriteLine("<tr><td colspan=\"{2}\">&nbsp;</td></tr>");
            }

            foreach (var withProblems in disassemblyResult.Methods
                    .Where(method => !string.IsNullOrEmpty(method.Problem))
                    .GroupBy(method => method.Problem))
            {
                logger.WriteLine($"<tr><td colspan=\"{2}\"><b>{withProblems.Key}</b></td></tr>");
                foreach (var withProblem in withProblems)
                {
                    logger.WriteLine($"<tr><td colspan=\"{2}\">{withProblem.Name}</td></tr>");
                }
                logger.WriteLine("<tr><td colspan=\"{2}\"></td></tr>");
            }

            logger.WriteLine("</tbody></table></body></html>");
        }
Esempio n. 22
0
        public void CanParseMonoDisassemblyOutput()
        {
            const string input = @"
CFA: [0] def_cfa: %rsp+0x8
CFA: [0] offset: unknown at cfa-0x8
CFA: [4] def_cfa_offset: 0x10
CFA: [8] offset: %r15 at cfa-0x10
Basic block 0 starting at offset 0xb
Basic block 2 starting at offset 0xb
Basic block 1 starting at offset 0x27
CFA: [2f] def_cfa: %rsp+0x8
Method void BenchmarkDotNet.Samples.CPU.Cpu_Atomics:NoLock () emitted at 0x1027cdf80 to 0x1027cdfb0 (code length 48) [BenchmarkDotNet.Samples.exe]
/var/folders/ld/p9yn04fs3ys6h_dkyxvv95_40000gn/T/.WuSVhL:
(__TEXT,__text) section
chmarkDotNet_Samples_CPU_Cpu_Atomics_NoLock:
0000000000000000	subq	$0x8, %rsp
0000000000000004	movq	%r15, (%rsp)
0000000000000008	movq	%rdi, %r15
000000000000000b	movslq	0x18(%r15), %rax
000000000000000f	incl	%eax
0000000000000011	movl	%eax, 0x18(%r15)
0000000000000015	incl	%eax
0000000000000017	movl	%eax, 0x18(%r15)
000000000000001b	incl	%eax
000000000000001d	movl	%eax, 0x18(%r15)
0000000000000021	incl	%eax
0000000000000023	movl	%eax, 0x18(%r15)
0000000000000027	movq	(%rsp), %r15
000000000000002b	addq	$0x8, %rsp
000000000000002f	retq"    ;

            var expected = new DisassemblyResult()
            {
                Methods = new[]
                {
                    new DisassembledMethod()
                    {
                        Name = "NoLock",
                        Maps = new[]
                        {
                            new Map()
                            {
                                Instructions = new[]
                                {
                                    new Diagnosers.Code {
                                        TextRepresentation = "subq\t$0x8, %rsp"
                                    },

                                    new Diagnosers.Code {
                                        TextRepresentation = "movq\t%r15, (%rsp)"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "movq\t%rdi, %r15"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "movslq\t0x18(%r15), %rax"
                                    },

                                    new Diagnosers.Code {
                                        TextRepresentation = "incl\t%eax"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "movl\t%eax, 0x18(%r15)"
                                    },

                                    new Diagnosers.Code {
                                        TextRepresentation = "incl\t%eax"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "movl\t%eax, 0x18(%r15)"
                                    },

                                    new Diagnosers.Code {
                                        TextRepresentation = "incl\t%eax"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "movl\t%eax, 0x18(%r15)"
                                    },

                                    new Diagnosers.Code {
                                        TextRepresentation = "incl\t%eax"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "movl\t%eax, 0x18(%r15)"
                                    },

                                    new Diagnosers.Code {
                                        TextRepresentation = "movq\t(%rsp), %r15"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "addq\t$0x8, %rsp"
                                    },
                                    new Diagnosers.Code {
                                        TextRepresentation = "retq"
                                    }
                                }
                            }
                        }
                    }
                }
            };

            var disassemblyResult = MonoDisassembler.OutputParser.Parse(
                input.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None),
                "NoLock", commandLine: string.Empty);

            Assert.Equal(expected.Methods.Single().Name, disassemblyResult.Methods.Single().Name);
            Assert.Equal(expected.Methods[0].Maps[0].Instructions.Length, disassemblyResult.Methods[0].Maps[0].Instructions.Length);

            for (int i = 0; i < expected.Methods[0].Maps[0].Instructions.Length; i++)
            {
                Assert.Equal(expected.Methods[0].Maps[0].Instructions[i].TextRepresentation,
                             disassemblyResult.Methods[0].Maps[0].Instructions[i].TextRepresentation);
            }
        }
        internal static IReadOnlyList <Element> Prettify(DisassembledMethod method, DisassemblyResult disassemblyResult, DisassemblyDiagnoserConfig config, string labelPrefix)
        {
            var asmInstructions = method.Maps.SelectMany(map => map.SourceCodes.OfType <Asm>()).ToArray();

            // first of all, we search of referenced addresses (jump|calls)
            var referencedAddresses = new HashSet <ulong>();

            foreach (var asm in asmInstructions)
            {
                if (ClrMdV2Disassembler.TryGetReferencedAddress(asm.Instruction, disassemblyResult.PointerSize, out ulong referencedAddress))
                {
                    referencedAddresses.Add(referencedAddress);
                }
            }

            // for every IP that is referenced, we emit a uinque label
            var addressesToLabels = new Dictionary <ulong, string>();
            int currentLabelIndex = 0;

            foreach (var instruction in asmInstructions)
            {
                if (referencedAddresses.Contains(instruction.InstructionPointer) && !addressesToLabels.ContainsKey(instruction.InstructionPointer))
                {
                    addressesToLabels.Add(instruction.InstructionPointer, $"{labelPrefix}_L{currentLabelIndex++:00}");
                }
            }

            var formatterWithLabelsSymbols = config.GetFormatterWithSymbolSolver(addressesToLabels);
            var formatterWithGlobalSymbols = config.GetFormatterWithSymbolSolver(disassemblyResult.AddressToNameMapping);

            var prettified = new List <Element>();

            foreach (var map in method.Maps)
            {
                foreach (var instruction in map.SourceCodes)
                {
                    if (instruction is Sharp sharp)
                    {
                        prettified.Add(new Element(sharp.Text, sharp));
                    }
                    else if (instruction is MonoCode mono)
                    {
                        prettified.Add(new Element(mono.Text, mono));
                    }
                    else if (instruction is Asm asm)
                    {
                        // this IP is referenced by some jump|call, so we add a label
                        if (addressesToLabels.TryGetValue(asm.InstructionPointer, out string label))
                        {
                            prettified.Add(new Label(label));
                        }

                        if (ClrMdV2Disassembler.TryGetReferencedAddress(asm.Instruction, disassemblyResult.PointerSize, out ulong referencedAddress))
                        {
                            // jump or a call within same method
                            if (addressesToLabels.TryGetValue(referencedAddress, out string translated))
                            {
                                prettified.Add(new Reference(InstructionFormatter.Format(asm.Instruction, formatterWithLabelsSymbols, config.PrintInstructionAddresses, disassemblyResult.PointerSize), translated, asm));
                                continue;
                            }

                            // call to a known method
                            if (disassemblyResult.AddressToNameMapping.ContainsKey(referencedAddress))
                            {
                                prettified.Add(new Element(InstructionFormatter.Format(asm.Instruction, formatterWithGlobalSymbols, config.PrintInstructionAddresses, disassemblyResult.PointerSize), asm));
                                continue;
                            }
                        }

                        prettified.Add(new Element(InstructionFormatter.Format(asm.Instruction, formatterWithGlobalSymbols, config.PrintInstructionAddresses, disassemblyResult.PointerSize), asm));
                    }
                }
            }

            return(prettified);
        }
 public bool TryDisassembleInstruction(ulong pc, byte[] data, uint flags, out DisassemblyResult result, int memoryOffset = 0)
 {
     return(GetDisassembler(flags).TryDisassembleInstruction(pc, data, flags, out result, memoryOffset));
 }