4 using System.Reflection;
5 using System.Diagnostics;
6 using System.Collections.Generic;
8 using Mono.CompilerServices.SymbolWriter;
13 public string FileName;
17 class LocationProvider {
18 class AssemblyLocationProvider {
19 AssemblyDefinition assembly;
20 MonoSymbolFile symbolFile;
21 string seqPointDataPath;
23 public AssemblyLocationProvider (AssemblyDefinition assembly, MonoSymbolFile symbolFile, string seqPointDataPath)
25 this.assembly = assembly;
26 this.symbolFile = symbolFile;
27 this.seqPointDataPath = seqPointDataPath;
30 public bool TryGetLocation (string methodFullName, string[] methodParamsTypes, int offset, bool isOffsetIL, out Location location)
32 location = default (Location);
33 if (symbolFile == null)
36 var typeNameEnd = methodFullName.LastIndexOf (".");
37 var typeName = methodFullName.Substring (0, typeNameEnd);
38 var methodName = methodFullName.Substring (typeNameEnd + 1, methodFullName.Length - typeNameEnd - 1);
40 var type = assembly.MainModule.Types.FirstOrDefault (t => t.FullName == typeName);
44 var method = type.Methods.FirstOrDefault (m => {
45 if (m.Name != methodName)
48 if (m.Parameters.Count != methodParamsTypes.Length)
51 for (var i = 0; i < methodParamsTypes.Length; i++) {
52 var paramType = m.Parameters[i].ParameterType;
53 if (paramType.Name != methodParamsTypes[i])
63 int ilOffset = (isOffsetIL)? offset : GetILOffsetFromFile (method.MetadataToken.ToInt32 (), offset);
67 var methodSymbol = symbolFile.Methods [method.MetadataToken.RID-1];
69 foreach (var lineNumber in methodSymbol.GetLineNumberTable ().LineNumbers) {
70 if (lineNumber.Offset < ilOffset)
73 location.FileName = symbolFile.Sources [lineNumber.File-1].FileName;
74 location.Line = lineNumber.Row;
81 static MethodInfo methodGetIL;
82 private int GetILOffsetFromFile (int methodToken, int nativeOffset)
84 if (string.IsNullOrEmpty (seqPointDataPath))
87 if (methodGetIL == null)
88 methodGetIL = typeof (StackFrame).GetMethod ("GetILOffsetFromFile", BindingFlags.NonPublic | BindingFlags.Static);
90 if (methodGetIL == null)
91 throw new Exception ("System.Diagnostics.StackFrame.GetILOffsetFromFile could not be found, make sure you have an updated mono installed.");
93 return (int) methodGetIL.Invoke (null, new object[] {seqPointDataPath, methodToken, nativeOffset});
97 Dictionary<string, AssemblyLocationProvider> assemblies;
98 HashSet<string> directories;
100 public LocationProvider () {
101 assemblies = new Dictionary<string, AssemblyLocationProvider> ();
102 directories = new HashSet<string> ();
105 public void AddAssembly (string assemblyPath)
107 assemblyPath = Path.GetFullPath (assemblyPath);
108 if (assemblies.ContainsKey (assemblyPath))
111 if (!File.Exists (assemblyPath))
112 throw new ArgumentException ("assemblyPath does not exist: "+ assemblyPath);
114 var assembly = AssemblyDefinition.ReadAssembly (assemblyPath);
115 MonoSymbolFile symbolFile = null;
117 var symbolPath = assemblyPath + ".mdb";
118 if (!File.Exists (symbolPath))
119 Debug.WriteLine (".mdb file was not found for " + assemblyPath);
121 symbolFile = MonoSymbolFile.ReadSymbolFile (assemblyPath + ".mdb");
123 var seqPointDataPath = assemblyPath + ".msym";
124 if (!File.Exists (seqPointDataPath))
125 seqPointDataPath = null;
127 assemblies.Add (assemblyPath, new AssemblyLocationProvider (assembly, symbolFile, seqPointDataPath));
129 directories.Add (Path.GetDirectoryName (assemblyPath));
131 foreach (var assemblyRef in assembly.MainModule.AssemblyReferences) {
132 string refPath = null;
133 foreach (var dir in directories) {
134 refPath = Path.Combine (dir, assemblyRef.Name);
135 if (File.Exists (refPath))
137 refPath = Path.Combine (dir, assemblyRef.Name + ".dll");
138 if (File.Exists (refPath))
140 refPath = Path.Combine (dir, assemblyRef.Name + ".exe");
141 if (File.Exists (refPath))
146 AddAssembly (refPath);
150 public void AddDirectory (string directory)
152 directory = Path.GetFullPath (directory);
153 if (!Directory.Exists (directory)) {
154 Console.Error.WriteLine ("Directory " + directory + " does not exist.");
158 directories.Add (directory);
161 public bool TryGetLocation (string methodName, string[] methodParams, int offset, bool isOffsetIL, out Location location)
163 location = default (Location);
164 foreach (var assembly in assemblies.Values) {
165 if (assembly.TryGetLocation (methodName, methodParams, offset, isOffsetIL, out location))