Merge pull request #896 from echampet/webresource
[mono.git] / mcs / tools / mono-symbolicate / symbolicate.cs
1 using System;
2 using System.IO;
3 using System.Globalization;
4 using System.Text.RegularExpressions;
5
6 namespace Symbolicate
7 {
8         public class Program
9         {
10                 static Regex regex = new Regex (@"\w*at (?<Method>.+) *(\[0x(?<IL>.+)\]|<0x.+ \+ 0x(?<NativeOffset>.+)>( (?<MethodIndex>\d+)|)) in <filename unknown>:0");
11
12                 public static int Main (String[] args)
13                 {
14                         if (args.Length < 2) {
15                                 Console.Error.WriteLine ("Usage: symbolicate <assembly path> <input file> [lookup directories]");
16                                 return 1;
17                         }
18
19                         var assemblyPath = args [0];
20                         var inputFile = args [1];
21
22                         var locProvider = new LocationProvider ();
23
24                         for (var i = 2; i < args.Length; i++)
25                                 locProvider.AddDirectory (args [i]);
26
27                         locProvider.AddAssembly (assemblyPath);
28
29                         using (StreamReader r = new StreamReader (inputFile)) {
30                             for (var line = r.ReadLine (); line != null; line = r.ReadLine ()) {
31                                         line = SymbolicateLine (line, locProvider);
32                                         Console.WriteLine (line);
33                             }
34                         }
35
36                         return 0;
37                 }
38
39                 static string SymbolicateLine (string line, LocationProvider locProvider)
40                 {
41                         var match = regex.Match (line);
42                         if (!match.Success)
43                                 return line;
44
45                         string typeFullName;
46                         var methodStr = match.Groups ["Method"].Value.Trim ();
47                         if (!TryParseMethodType (methodStr, out typeFullName))
48                                 return line;
49
50                         var isOffsetIL = !string.IsNullOrEmpty (match.Groups ["IL"].Value);
51                         var offsetVarName = (isOffsetIL)? "IL" : "NativeOffset";
52                         var offset = int.Parse (match.Groups [offsetVarName].Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
53
54                         uint methodIndex = 0xffffff;
55                         if (!string.IsNullOrEmpty (match.Groups ["MethodIndex"].Value))
56                                 methodIndex = uint.Parse (match.Groups ["MethodIndex"].Value, CultureInfo.InvariantCulture);
57
58                         Location location;
59                         if (!locProvider.TryGetLocation (methodStr, typeFullName, offset, isOffsetIL, methodIndex, out location))
60                                 return line;
61
62                         return line.Replace ("<filename unknown>:0", string.Format ("{0}:{1}", location.FileName, location.Line));
63                 }
64
65                 static bool TryParseMethodType (string str, out string typeFullName)
66                 {
67                         typeFullName = null;
68
69                         var methodNameEnd = str.IndexOf ("(");
70                         if (methodNameEnd == -1)
71                                 return false;
72
73                         // Remove parameters
74                         str = str.Substring (0, methodNameEnd);
75
76                         // Remove generic parameters
77                         str = Regex.Replace (str, @"\[[^\[\]]*\]", "");
78
79                         var typeNameEnd = str.LastIndexOf (".");
80                         if (methodNameEnd == -1 || typeNameEnd == -1)
81                                 return false;
82
83                         // Remove method name
84                         typeFullName = str.Substring (0, typeNameEnd);
85
86                         return true;
87                 }
88         }
89 }