5 using System.Reflection;
6 using System.Diagnostics;
7 using System.Collections.Generic;
9 using Mono.CompilerServices.SymbolWriter;
10 using System.Runtime.InteropServices;
15 public string FileName;
19 class LocationProvider {
20 class AssemblyLocationProvider {
22 MonoSymbolFile symbolFile;
23 string seqPointDataPath;
25 public AssemblyLocationProvider (Assembly assembly, MonoSymbolFile symbolFile, string seqPointDataPath)
27 this.assembly = assembly;
28 this.symbolFile = symbolFile;
29 this.seqPointDataPath = seqPointDataPath;
32 public bool TryGetLocation (string methodStr, string typeFullName, int offset, bool isOffsetIL, uint methodIndex, out Location location)
34 location = default (Location);
35 if (symbolFile == null)
38 var type = assembly.GetTypes().FirstOrDefault (t => t.FullName == typeFullName);
42 var bindingflags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
43 var method = type.GetMethods(bindingflags).FirstOrDefault (m => GetMethodFullName (m) == methodStr);
47 int ilOffset = (isOffsetIL)? offset : GetILOffsetFromFile (method.MetadataToken, methodIndex, offset);
51 var methodSymbol = symbolFile.Methods [(method.MetadataToken & 0x00ffffff) - 1];
53 var lineNumbers = methodSymbol.GetLineNumberTable ().LineNumbers;
54 var lineNumber = lineNumbers.FirstOrDefault (l => l.Offset >= ilOffset) ?? lineNumbers.Last ();
56 location.FileName = symbolFile.Sources [lineNumber.File-1].FileName;
57 location.Line = lineNumber.Row;
61 [DllImport("mono-symbolicate-native.dll")]
62 private static extern bool mono_seq_point_data_get_il_offset (string path, uint method_token, uint method_index, uint native_offset, out uint il_offset);
64 static MethodInfo methodGetIL;
65 private int GetILOffsetFromFile (int methodToken, uint methodIndex, int nativeOffset)
68 mono_seq_point_data_get_il_offset (seqPointDataPath, (uint) methodToken, methodIndex, (uint) nativeOffset, out ilOffset);
70 return (int) ilOffset;
73 private string GetMethodFullName (MethodBase m)
75 StringBuilder sb = new StringBuilder ();
77 StackTraceHelper.GetFullNameForStackTrace (sb, m);
79 return sb.ToString ();
83 Dictionary<string, AssemblyLocationProvider> assemblies;
84 HashSet<string> directories;
86 public LocationProvider () {
87 assemblies = new Dictionary<string, AssemblyLocationProvider> ();
88 directories = new HashSet<string> ();
91 public void AddAssembly (string assemblyPath)
93 assemblyPath = Path.GetFullPath (assemblyPath);
94 if (assemblies.ContainsKey (assemblyPath))
97 if (!File.Exists (assemblyPath))
98 throw new ArgumentException ("assemblyPath does not exist: "+ assemblyPath);
100 var assembly = Assembly.ReflectionOnlyLoadFrom (assemblyPath);
101 MonoSymbolFile symbolFile = null;
103 var symbolPath = assemblyPath + ".mdb";
104 if (!File.Exists (symbolPath))
105 Debug.WriteLine (".mdb file was not found for " + assemblyPath);
107 symbolFile = MonoSymbolFile.ReadSymbolFile (assemblyPath + ".mdb");
109 var seqPointDataPath = assemblyPath + ".msym";
110 if (!File.Exists (seqPointDataPath))
111 seqPointDataPath = null;
113 assemblies.Add (assemblyPath, new AssemblyLocationProvider (assembly, symbolFile, seqPointDataPath));
115 directories.Add (Path.GetDirectoryName (assemblyPath));
117 foreach (var assemblyRef in assembly.GetReferencedAssemblies ()) {
118 string refPath = null;
119 foreach (var dir in directories) {
120 refPath = Path.Combine (dir, assemblyRef.Name);
121 if (File.Exists (refPath))
123 refPath = Path.Combine (dir, assemblyRef.Name + ".dll");
124 if (File.Exists (refPath))
126 refPath = Path.Combine (dir, assemblyRef.Name + ".exe");
127 if (File.Exists (refPath))
132 AddAssembly (refPath);
136 public void AddDirectory (string directory)
138 directory = Path.GetFullPath (directory);
139 if (!Directory.Exists (directory)) {
140 Console.Error.WriteLine ("Directory " + directory + " does not exist.");
144 directories.Add (directory);
147 public bool TryGetLocation (string method, string typeFullName, int offset, bool isOffsetIL, uint methodIndex, out Location location)
149 location = default (Location);
150 foreach (var assembly in assemblies.Values) {
151 if (assembly.TryGetLocation (method, typeFullName, offset, isOffsetIL, methodIndex, out location))