Added Mono.Tasklets test
[mono.git] / mcs / tools / mono-symbolicate / LocationProvider.cs
1 using System;
2 using System.IO;
3 using System.Linq;
4 using System.Text;
5 using System.Collections.Generic;
6 using Mono.Cecil;
7 using Mono.Cecil.Cil;
8 using Mono.Collections.Generic;
9
10 namespace Mono
11 {
12         class AssemblyLocationProvider
13         {
14                 AssemblyDefinition assembly;
15
16                 public AssemblyLocationProvider (string assemblyPath)
17                 {
18                         assemblyPath = Path.GetFullPath (assemblyPath);
19
20                         if (!File.Exists (assemblyPath))
21                                 throw new ArgumentException ("assemblyPath does not exist: "+ assemblyPath);
22
23                         var readerParameters = new ReaderParameters { ReadSymbols = true };
24                         assembly = AssemblyDefinition.ReadAssembly (assemblyPath, readerParameters);
25                 }
26
27                 public bool TryResolveLocation (StackFrameData sfData, SeqPointInfo seqPointInfo)
28                 {
29                         if (!assembly.MainModule.HasSymbols)
30                                 return false;
31
32                         TypeDefinition type = null;
33                         var nested = sfData.TypeFullName.Split ('+');
34                         var types = assembly.MainModule.Types;
35                         foreach (var ntype in nested) {
36                                 type = types.FirstOrDefault (t => t.Name == ntype);
37                                 if (type == null)
38                                         return false;
39
40                                 types = type.NestedTypes;
41                         }
42
43                         var parensStart = sfData.MethodSignature.IndexOf ('(');
44                         var methodName = sfData.MethodSignature.Substring (0, parensStart).TrimEnd ();
45                         var methodParameters = sfData.MethodSignature.Substring (parensStart);
46                         var method = type.Methods.FirstOrDefault (m => CompareName (m, methodName) && CompareParameters (m.Parameters, methodParameters));
47                         if (method == null)
48                                 return false;
49
50                         int ilOffset;
51                         if (sfData.IsILOffset) {
52                                 ilOffset = sfData.Offset;
53                         } else {
54                                 if (seqPointInfo == null)
55                                         return false;
56
57                                 ilOffset = seqPointInfo.GetILOffset (method.MetadataToken.ToInt32 (), sfData.MethodIndex, sfData.Offset);
58                         }
59
60                         if (ilOffset < 0)
61                                 return false;
62
63                         SequencePoint sp = null;
64                         foreach (var instr in method.Body.Instructions) {
65                                 if (instr.SequencePoint != null)
66                                         sp = instr.SequencePoint;
67                                 
68                                 if (instr.Offset >= ilOffset) {
69                                         sfData.SetLocation (sp.Document.Url, sp.StartLine);
70                                         return true;
71                                 }
72                         }
73
74                         return false;
75                 }
76
77                 static bool CompareName (MethodDefinition candidate, string expected)
78                 {
79                         if (candidate.Name == expected)
80                                 return true;
81
82                         if (!candidate.HasGenericParameters)
83                                 return false;
84                         
85                         var genStart = expected.IndexOf ('[');
86                         if (genStart < 0)
87                                 return false;
88
89                         if (candidate.Name != expected.Substring (0, genStart))
90                                 return false;
91
92                         int arity = 1;
93                         for (int pos = genStart; pos < expected.Length; ++pos) {
94                                 if (expected [pos] == ',')
95                                         ++arity;
96                         }
97
98                         return candidate.GenericParameters.Count == arity;
99                 }
100
101                 static bool CompareParameters (Collection<ParameterDefinition> candidate, string expected)
102                 {
103                         var builder = new StringBuilder ();
104                         builder.Append ("(");
105
106                         for (int i = 0; i < candidate.Count; i++) {
107                                 var parameter = candidate [i];
108                                 if (i > 0)
109                                         builder.Append (", ");
110
111                                 if (parameter.ParameterType.IsSentinel)
112                                         builder.Append ("...,");
113
114                                 var pt = parameter.ParameterType;
115                                 if (!string.IsNullOrEmpty (pt.Namespace)) {
116                                         builder.Append (pt.Namespace);
117                                         builder.Append (".");
118                                 }
119
120                                 FormatElementType (pt, builder);
121
122                                 builder.Append (" ");
123                                 builder.Append (parameter.Name);
124                         }
125
126                         builder.Append (")");
127
128                         return builder.ToString () == expected;
129                 }
130
131                 static void FormatElementType (TypeReference tr, StringBuilder builder)
132                 {
133                         var ts = tr as TypeSpecification;
134                         if (ts != null) {
135                                 if (ts.IsByReference) {
136                                         FormatElementType (ts.ElementType, builder);
137                                         builder.Append ("&");
138                                         return;
139                                 }
140
141                                 var array = ts as ArrayType;
142                                 if (array != null) {
143                                         FormatElementType (ts.ElementType, builder);
144                                         builder.Append ("[");
145
146                                         for (int ii = 0; ii < array.Rank - 1; ++ii) {
147                                                 builder.Append (",");
148                                         }
149
150                                         builder.Append ("]");
151                                         return;
152                                 }
153                         }
154
155                         builder.Append (tr.Name);
156                 }
157         }
158 }
159