Пример #1
0
        private static void PrintILToNativeOffsetAlternative(ClrMethod method, IList <string> lines)
        {
            DesktopModule module = (DesktopModule)@method.Type.Module;

            if (!module.IsPdbLoaded)
            {
                // Have to load the Pdb, if it's not already loaded!!
                string val = module.TryDownloadPdb(null);
                if (val != null)
                {
                    module.LoadPdb(val);
                }
            }

            foreach (var location in module.GetSourceLocationsForMethod(@method.MetadataToken))
            {
                ILOffsetSourceLocation ILLocation = location;
                var ilMaps = @method.ILOffsetMap.Where(il => il.ILOffset == ILLocation.ILOffset);
                Console.WriteLine("{0:X8} -> {1}:{2}",
                                  location.ILOffset,
                                  Path.GetFileName(location.SourceLocation.FilePath),
                                  location.SourceLocation.LineNumber);
                Console.WriteLine("  " + String.Join("\n  ",
                                                     ilMaps.Select(
                                                         ilMap =>
                                                         String.Format("[{0:X8}-{1:X8} ({2:X8}-{3:X8})] ILOffset: {4:X2}",
                                                                       ilMap.StartAddress - @method.NativeCode,
                                                                       ilMap.EndAddress - @method.NativeCode,
                                                                       ilMap.StartAddress, ilMap.EndAddress, ilMap.ILOffset))));
                var indent = 7;
                Console.WriteLine("{0,6}:{1}", location.SourceLocation.LineNumber, lines[location.SourceLocation.LineNumber - 1]);
                Console.WriteLine(new string(' ', location.SourceLocation.ColStart - 1 + indent) +
                                  new string('*', location.SourceLocation.ColEnd - location.SourceLocation.ColStart));
            }
            Console.WriteLine();
        }
        /// <summary>
        /// Code from http://stackoverflow.com/questions/2057781/is-there-a-way-to-get-the-stacktraces-for-all-threads-in-c-like-java-lang-thre/24315960#24315960
        /// also see http://stackoverflow.com/questions/31633541/clrmd-throws-exception-when-creating-runtime/31745689#31745689
        /// </summary>
        public void PrintCodeForMethod(Benchmark benchmark, Process process, IBenchmarkLogger logger, bool printAssembly, bool printIL, bool printDiagnostics)
        {
            this.process = process;
            this.logger  = logger;

            //Method name format: "BenchmarkDotNet.Samples.Infra.RunFast()" (NOTE: WITHOUT the return type)
            var methodInfo = benchmark.Target.Method;

            fullTypeName = methodInfo.DeclaringType.FullName;

            var methodParams = string.Join(", ", methodInfo.GetParameters().Select(p => p.ParameterType.FullName));

            fullMethodName = $"{fullTypeName}.{methodInfo.Name}({methodParams})";

            logger?.WriteLine($"\nPrinting Code for Method: {fullMethodName}");
            logger?.WriteLine($"\nPrintAssembly={printAssembly}, PrintIL={printIL}");
            logger?.WriteLine($"Attaching to process {Path.GetFileName(process.MainModule.FileName)}, Pid={process.Id}");
            logger?.WriteLine($"Path {process.MainModule.FileName}");
            using (var dataTarget = DataTarget.AttachToProcess(process.Id, 5000, AttachFlag.NonInvasive))
            {
                var runtime = SetupClrRuntime(dataTarget);
                if (printDiagnostics)
                {
                    PrintRuntimeDiagnosticInfo(dataTarget, runtime);
                }

                if (printAssembly == false && printIL == false)
                {
                    return;
                }

                ClrType       @class  = runtime.GetHeap().GetTypeByName(fullTypeName);
                ClrMethod     @method = @class.Methods.Single(m => m.GetFullSignature() == fullMethodName);
                DesktopModule module  = (DesktopModule)@method.Type.Module;
                if (!module.IsPdbLoaded)
                {
                    string pdbLocation = module.TryDownloadPdb(null);
                    if (pdbLocation != null)
                    {
                        module.LoadPdb(pdbLocation);
                    }
                }

                logger?.WriteLine($"Module: {Path.GetFileName(module.Name)}");
                logger?.WriteLine($"Type: {method.Type.Name}");
                logger?.WriteLine($"Method: {method.Name}");

                // TODO work out why this returns locations inside OTHER methods, it's like it doesn't have an upper bound and just keeps going!?
                var ilOffsetLocations = module.GetSourceLocationsForMethod(@method.MetadataToken);

                string   filePath = null;
                string[] lines    = null;
                logger?.WriteLine("");
                for (int i = 0; i < ilOffsetLocations.Count; i++)
                {
                    var location = ilOffsetLocations[i];
                    var ilMaps   = @method.ILOffsetMap.Where(il => il.ILOffset == location.ILOffset).ToList();
                    if (ilMaps.Any() == false)
                    {
                        continue;
                    }

                    if (lines == null || location.SourceLocation.FilePath != filePath)
                    {
                        filePath = location.SourceLocation.FilePath;
                        lines    = File.ReadAllLines(filePath);
                        logger?.WriteLine($"Parsing file {Path.GetFileName(location.SourceLocation.FilePath)}");
                    }

                    PrintLocationAndILMapInfo(@method, location, ilMaps);
                    PrintSourceCode(lines, location);

                    if (printAssembly)
                    {
                        var debugControl = dataTarget.DebuggerInterface as IDebugControl;
                        PrintAssemblyCode(@method, ilMaps, runtime, debugControl);
                    }
                }
            }
        }