[msvc] Update csproj files (#4074)
[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                 Logger logger;
16
17                 public AssemblyLocationProvider (string assemblyPath, Logger logger)
18                 {
19                         assemblyPath = Path.GetFullPath (assemblyPath);
20                         this.logger = logger;
21
22                         if (!File.Exists (assemblyPath))
23                                 throw new ArgumentException ("assemblyPath does not exist: "+ assemblyPath);
24
25                         var readerParameters = new ReaderParameters { ReadSymbols = true };
26                         assembly = AssemblyDefinition.ReadAssembly (assemblyPath, readerParameters);
27                 }
28
29                 public bool TryResolveLocation (StackFrameData sfData, SeqPointInfo seqPointInfo)
30                 {
31                         if (!assembly.MainModule.HasSymbols)
32                                 return false;
33
34                         TypeDefinition type = null;
35                         var nested = sfData.TypeFullName.Split ('+');
36                         var types = assembly.MainModule.Types;
37                         foreach (var ntype in nested) {
38                                 if (type == null) {
39                                         // Use namespace first time.
40                                         type = types.FirstOrDefault (t => t.FullName == ntype);
41                                 } else {
42                                         type = types.FirstOrDefault (t => t.Name == ntype);
43                                 }
44
45                                 if (type == null) {
46                                         logger.LogWarning ("Could not find type: {0}", ntype);
47                                         return false;
48                                 }
49
50                                 types = type.NestedTypes;
51                         }
52
53                         var parensStart = sfData.MethodSignature.IndexOf ('(');
54                         var methodName = sfData.MethodSignature.Substring (0, parensStart).TrimEnd ();
55                         var methodParameters = sfData.MethodSignature.Substring (parensStart);
56                         var method = type.Methods.FirstOrDefault (m => CompareName (m, methodName) && CompareParameters (m.Parameters, methodParameters));
57                         if (method == null) {
58                                 logger.LogWarning ("Could not find method: {0}", methodName);
59                                 return false;
60                         }
61
62                         int ilOffset;
63                         if (sfData.IsILOffset) {
64                                 ilOffset = sfData.Offset;
65                         } else {
66                                 if (seqPointInfo == null)
67                                         return false;
68
69                                 ilOffset = seqPointInfo.GetILOffset (method.MetadataToken.ToInt32 (), sfData.MethodIndex, sfData.Offset);
70                         }
71
72                         if (ilOffset < 0)
73                                 return false;
74
75                         if (!method.DebugInformation.HasSequencePoints)
76                                 return false;
77
78                         SequencePoint prev = null;
79                         foreach (var sp in method.DebugInformation.SequencePoints.OrderBy (l => l.Offset)) {
80                                 if (sp.Offset >= ilOffset) {
81                                         sfData.SetLocation (sp.Document.Url, sp.StartLine);
82                                         return true;
83                                 }
84
85                                 prev = sp;
86                         }
87
88                         if (prev != null) {
89                                 sfData.SetLocation (prev.Document.Url, prev.StartLine);
90                                 return true;
91                         }
92
93                         return false;
94                 }
95
96                 static bool CompareName (MethodDefinition candidate, string expected)
97                 {
98                         if (candidate.Name == expected)
99                                 return true;
100
101                         if (!candidate.HasGenericParameters)
102                                 return false;
103                         
104                         var genStart = expected.IndexOf ('[');
105                         if (genStart < 0)
106                                 return false;
107
108                         if (candidate.Name != expected.Substring (0, genStart))
109                                 return false;
110
111                         int arity = 1;
112                         for (int pos = genStart; pos < expected.Length; ++pos) {
113                                 if (expected [pos] == ',')
114                                         ++arity;
115                         }
116
117                         return candidate.GenericParameters.Count == arity;
118                 }
119
120                 static bool CompareParameters (Collection<ParameterDefinition> candidate, string expected)
121                 {
122                         var builder = new StringBuilder ();
123                         builder.Append ("(");
124
125                         for (int i = 0; i < candidate.Count; i++) {
126                                 var parameter = candidate [i];
127                                 if (i > 0)
128                                         builder.Append (", ");
129
130                                 if (parameter.ParameterType.IsSentinel)
131                                         builder.Append ("...,");
132
133                                 var pt = parameter.ParameterType;
134                                 if (!string.IsNullOrEmpty (pt.Namespace)) {
135                                         builder.Append (pt.Namespace);
136                                         builder.Append (".");
137                                 }
138
139                                 FormatElementType (pt, builder);
140
141                                 builder.Append (" ");
142                                 builder.Append (parameter.Name);
143                         }
144
145                         builder.Append (")");
146
147                         return builder.ToString () == expected;
148                 }
149
150                 static void FormatElementType (TypeReference tr, StringBuilder builder)
151                 {
152                         var ts = tr as TypeSpecification;
153                         if (ts != null) {
154                                 if (ts.IsByReference) {
155                                         FormatElementType (ts.ElementType, builder);
156                                         builder.Append ("&");
157                                         return;
158                                 }
159
160                                 var array = ts as ArrayType;
161                                 if (array != null) {
162                                         FormatElementType (ts.ElementType, builder);
163                                         builder.Append ("[");
164
165                                         for (int ii = 0; ii < array.Rank - 1; ++ii) {
166                                                 builder.Append (",");
167                                         }
168
169                                         builder.Append ("]");
170                                         return;
171                                 }
172                         }
173
174                         builder.Append (tr.Name);
175                 }
176         }
177 }
178