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); } } } }