[corlib] Removed MVID and AOTID metadata.
[mono.git] / mcs / class / corlib / System.Diagnostics / StackTrace.cs
1 //
2 // System.Diagnostics.StackTrace.cs
3 //
4 // Author:
5 //      Alexander Klyubin (klyubin@aqris.com)
6 //      Dietmar Maurer (dietmar@ximian.com)
7 //
8 // (C) 2001
9 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System.Collections.Generic;
32 using System.Globalization;
33 using System.Reflection;
34 using System.Runtime.CompilerServices;
35 using System.Runtime.InteropServices;
36 using System.Security;
37 using System.Security.Permissions;
38 using System.Text;
39 using System.Threading;
40 using System.IO;
41
42 namespace System.Diagnostics {
43
44         [Serializable]
45         [ComVisible (true)]
46         [MonoTODO ("Serialized objects are not compatible with .NET")]
47         public class StackTrace {
48
49         // TraceFormat is Used to specify options for how the 
50         // string-representation of a StackTrace should be generated.
51         internal enum TraceFormat 
52         {
53             Normal,
54             TrailingNewLine,        // include a trailing new line character
55             NoResourceLookup    // to prevent infinite resource recusion
56         }
57
58                 public const int METHODS_TO_SKIP = 0;
59
60                 private StackFrame[] frames;
61                 readonly StackTrace[] captured_traces;
62                 private bool debug_info;
63
64                 private static Dictionary<string, Func<StackTrace, string>> metadataHandlers;
65
66                 [MethodImplAttribute (MethodImplOptions.NoInlining)]
67                 public StackTrace ()
68                 {
69                         init_frames (METHODS_TO_SKIP, false);
70                 }
71
72                 [MethodImplAttribute (MethodImplOptions.NoInlining)]
73                 public StackTrace (bool fNeedFileInfo)
74                 {
75                         init_frames (METHODS_TO_SKIP, fNeedFileInfo);
76                 }
77
78                 [MethodImplAttribute (MethodImplOptions.NoInlining)]
79                 public StackTrace (int skipFrames)
80                 {
81                         init_frames (skipFrames, false);
82                 }
83
84                 [MethodImplAttribute (MethodImplOptions.NoInlining)]
85                 public StackTrace (int skipFrames, bool fNeedFileInfo)
86                 {
87                         init_frames (skipFrames, fNeedFileInfo);
88                 }
89
90                 [MethodImplAttribute (MethodImplOptions.NoInlining)]
91                 void init_frames (int skipFrames, bool fNeedFileInfo)
92                 {
93                         if (skipFrames < 0)
94                                 throw new ArgumentOutOfRangeException ("< 0", "skipFrames");
95
96                         StackFrame sf;
97                         var l = new List<StackFrame> ();
98
99                         skipFrames += 2;
100                         
101                         while ((sf = new StackFrame (skipFrames, fNeedFileInfo)) != null &&
102                                sf.GetMethod () != null) {
103                                 
104                                 l.Add (sf);
105                                 skipFrames++;
106                         };
107
108                         debug_info = fNeedFileInfo;
109                         frames = l.ToArray ();
110                 }
111                 
112                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
113                 extern static StackFrame [] get_trace (Exception e, int skipFrames, bool fNeedFileInfo);
114
115                 public StackTrace (Exception e)
116                         : this (e, METHODS_TO_SKIP, false)
117                 {
118                 }
119
120                 public StackTrace (Exception e, bool fNeedFileInfo)
121                         : this (e, METHODS_TO_SKIP, fNeedFileInfo)
122                 {
123                 }
124
125                 public StackTrace (Exception e, int skipFrames)
126                         : this (e, skipFrames, false)
127                 {
128                 }
129
130                 public StackTrace (Exception e, int skipFrames, bool fNeedFileInfo)
131                 {
132                         if (e == null)
133                                 throw new ArgumentNullException ("e");
134                         if (skipFrames < 0)
135                                 throw new ArgumentOutOfRangeException ("< 0", "skipFrames");
136
137                         frames = get_trace (e, skipFrames, fNeedFileInfo);
138
139                         captured_traces = e.captured_traces;
140                 }
141
142                 public StackTrace (StackFrame frame)
143                 {
144                         this.frames = new StackFrame [1];
145                         this.frames [0] = frame;
146                 }
147
148                 [MonoLimitation ("Not possible to create StackTraces from other threads")]
149                 [Obsolete]
150                 public StackTrace (Thread targetThread, bool needFileInfo)
151                 {
152                         if (targetThread == Thread.CurrentThread){
153                                 init_frames (METHODS_TO_SKIP, needFileInfo);
154                                 return;
155                         }
156                         
157                         throw new NotImplementedException ();
158                 }
159
160                 internal StackTrace (StackFrame[] frames) {
161                         this.frames = frames;
162                 }
163
164                 public virtual int FrameCount {
165                         get {
166                                 return (frames == null) ? 0 : frames.Length;
167                         }
168                 }
169
170                 public virtual StackFrame GetFrame (int index)
171                 {
172                         if ((index < 0) || (index >= FrameCount)) {
173                                 return null;
174                         }
175
176                         return frames [index];
177                 }
178
179                 [ComVisibleAttribute (false)]
180                 public virtual StackFrame[] GetFrames ()
181                 {
182                         return frames;
183                 }
184
185                 static bool isAotidSet;
186                 static string aotid;
187                 static string GetAotId ()
188                 {
189                         if (!isAotidSet) {
190                                 aotid = Assembly.GetAotId ();
191                                 if (aotid != null)
192                                         aotid = new Guid (aotid).ToString ("N");
193                                 isAotidSet = true;
194                         }
195
196                         return aotid;
197                 }
198
199                 bool AddFrames (StringBuilder sb)
200                 {
201                         bool printOffset;
202                         string debugInfo, indentation;
203                         string unknown = Locale.GetText ("<unknown method>");
204
205                         indentation = "  ";
206                         debugInfo = Locale.GetText (" in {0}:{1} ");
207
208                         var newline = String.Format ("{0}{1}{2} ", Environment.NewLine, indentation,
209                                         Locale.GetText ("at"));
210
211                         int i;
212                         for (i = 0; i < FrameCount; i++) {
213                                 StackFrame frame = GetFrame (i);
214                                 if (i == 0)
215                                         sb.AppendFormat ("{0}{1} ", indentation, Locale.GetText ("at"));
216                                 else
217                                         sb.Append (newline);
218
219                                 if (frame.GetMethod () == null) {
220                                         string internal_name = frame.GetInternalMethodName ();
221                                         if (internal_name != null)
222                                                 sb.Append (internal_name);
223                                         else
224                                                 sb.AppendFormat ("<0x{0:x5} + 0x{1:x5}> {2}", frame.GetMethodAddress (), frame.GetNativeOffset (), unknown);
225                                 } else {
226                                         GetFullNameForStackTrace (sb, frame.GetMethod ());
227
228                                         if (frame.GetILOffset () == -1) {
229                                                 sb.AppendFormat (" <0x{0:x5} + 0x{1:x5}>", frame.GetMethodAddress (), frame.GetNativeOffset ());
230                                                 if (frame.GetMethodIndex () != 0xffffff)
231                                                         sb.AppendFormat (" {0}", frame.GetMethodIndex ());
232                                         } else {
233                                                 sb.AppendFormat (" [0x{0:x5}]", frame.GetILOffset ());
234                                         }
235
236                                         var filename = frame.GetSecureFileName ();
237                                         if (filename[0] == '<') {
238                                                 var mvid = frame.GetMethod ().Module.ModuleVersionId.ToString ("N");
239                                                 var aotid = GetAotId ();
240                                                 if (frame.GetILOffset () != -1 || aotid == null) {
241                                                         filename = string.Format ("<{0}>", mvid);
242                                                 } else {
243                                                         filename = string.Format ("<{0}#{1}>", mvid, aotid);
244                                                 }
245                                         }
246
247                                         sb.AppendFormat (debugInfo, filename, frame.GetFileLineNumber ());
248                                 }
249                         }
250
251                         return i != 0;
252                 }
253
254                 public static void GetFullNameForStackTrace (StringBuilder sb, MethodBase mi)
255                 {
256                         var declaringType = mi.DeclaringType;
257                         if (declaringType.IsGenericType && !declaringType.IsGenericTypeDefinition)
258                                 declaringType = declaringType.GetGenericTypeDefinition ();
259
260                         // Get generic definition
261                         const BindingFlags bindingflags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
262                         foreach (var m in declaringType.GetMethods (bindingflags)) {
263                                 if (m.MetadataToken == mi.MetadataToken) {
264                                         mi = m;
265                                         break;
266                                 }
267                         }
268
269                         sb.Append (declaringType.ToString ());
270
271                         sb.Append (".");
272                         sb.Append (mi.Name);
273
274                         if (mi.IsGenericMethod) {
275                                 Type[] gen_params = mi.GetGenericArguments ();
276                                 sb.Append ("[");
277                                 for (int j = 0; j < gen_params.Length; j++) {
278                                         if (j > 0)
279                                                 sb.Append (",");
280                                         sb.Append (gen_params [j].Name);
281                                 }
282                                 sb.Append ("]");
283                         }
284
285                         ParameterInfo[] p = mi.GetParameters ();
286
287                         sb.Append (" (");
288                         for (int i = 0; i < p.Length; ++i) {
289                                 if (i > 0)
290                                         sb.Append (", ");
291
292                                 Type pt = p[i].ParameterType;
293                                 if (pt.IsGenericType && ! pt.IsGenericTypeDefinition)
294                                         pt = pt.GetGenericTypeDefinition ();
295
296                                 sb.Append (pt.ToString());
297
298                                 if (p [i].Name != null) {
299                                         sb.Append (" ");
300                                         sb.Append (p [i].Name);
301                                 }
302                         }
303                         sb.Append (")");
304                 }               
305
306                 public override string ToString ()
307                 {
308                         StringBuilder sb = new StringBuilder ();
309
310                         //
311                         // Add traces captured using ExceptionDispatchInfo
312                         //
313                         if (captured_traces != null) {
314                                 foreach (var t in captured_traces) {
315                                         if (!t.AddFrames (sb))
316                                                 continue;
317
318                                         sb.Append (Environment.NewLine);
319                                         sb.Append ("--- End of stack trace from previous location where exception was thrown ---");
320                                         sb.Append (Environment.NewLine);
321                                 }
322                         }
323
324                         AddFrames (sb);
325
326                         return sb.ToString ();
327                 }
328
329                 internal String ToString (TraceFormat traceFormat)
330                 {
331                         // TODO:
332                         return ToString ();
333                 }
334         }
335 }