Merge pull request #1624 from esdrubal/getprocesstimes
[mono.git] / mcs / class / corlib / System / Exception.cs
1 //
2 // System.Exception.cs
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Patrik Torstensson
7 //
8 // (C) Ximian, Inc.  http://www.ximian.com
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;
32 using System.Collections.Generic;
33 using System.Diagnostics;
34 using System.Reflection;
35 using System.Text;
36 using System.Runtime.InteropServices;
37 using System.Runtime.CompilerServices;
38 using System.Runtime.Serialization;
39 using System.Security.Permissions;
40
41 namespace System
42 {
43         [Serializable]
44         [ComVisible(true)]
45         [ComDefaultInterface (typeof (_Exception))]
46         [ClassInterface (ClassInterfaceType.None)]
47         [StructLayout (LayoutKind.Sequential)]
48 #if MOBILE
49         public class Exception : ISerializable
50 #else
51         public class Exception : ISerializable, _Exception
52 #endif
53         {
54 #pragma warning disable 169, 649
55                 #region Sync with object-internals.h
56                 /* Stores the IPs and the generic sharing infos
57                    (vtable/MRGCTX) of the frames. */
58                 IntPtr [] trace_ips;
59                 Exception inner_exception;
60                 internal string message;
61                 string help_link;
62                 string class_name;
63                 string stack_trace;
64                 // formerly known as remote_stack_trace (see #425512):
65                 string _remoteStackTraceString;
66                 int remote_stack_index;
67                 internal int hresult = -2146233088;
68                 string source;
69                 IDictionary _data;
70                 StackTrace[] captured_traces;
71                 IntPtr[] native_trace_ips;
72                 #endregion
73 #pragma warning restore 169, 649
74
75                 /* Don't add fields here, the runtime depends on the layout of subclasses */
76
77                 public Exception ()
78                 {
79                 }
80
81                 public Exception (string message)
82                 {
83                         this.message = message;
84                 }
85
86                 protected Exception (SerializationInfo info, StreamingContext context)
87                 {
88                         if (info == null)
89                                 throw new ArgumentNullException ("info");
90
91                         class_name          = info.GetString ("ClassName");
92                         message             = info.GetString ("Message");
93                         help_link           = info.GetString ("HelpURL");
94                         stack_trace         = info.GetString ("StackTraceString");
95                         _remoteStackTraceString  = info.GetString ("RemoteStackTraceString");
96                         remote_stack_index  = info.GetInt32  ("RemoteStackIndex");
97                         hresult             = info.GetInt32  ("HResult");
98                         source              = info.GetString ("Source");
99                         inner_exception     = (Exception) info.GetValue ("InnerException", typeof (Exception));
100
101                         try {
102                                 _data = (IDictionary) info.GetValue ("Data", typeof (IDictionary));
103                         } catch (SerializationException) {
104                                 // member did not exist in .NET 1.x
105                         }
106                 }
107
108                 public Exception (string message, Exception innerException)
109                 {
110                         inner_exception = innerException;
111                         this.message = message;
112                 }
113
114                 public Exception InnerException {
115                         get { return inner_exception; }
116                 }
117
118                 public virtual string HelpLink {
119                         get { return help_link; }
120                         set { help_link = value; }
121                 }
122
123                 public int HResult {
124                         get { return hresult; }
125                         protected set { hresult = value; }
126                 }
127                 
128                 internal void SetErrorCode(int hr)
129                 {
130                         HResult = hr;
131                 }
132
133                 internal void SetMessage (string s)
134                 {
135                         message = s;
136                 }
137
138                 internal void SetStackTrace (string s)
139                 {
140                         stack_trace = s;
141                 }
142
143                 string ClassName {
144                         get {
145                                 if (class_name == null)
146                                         class_name = GetType ().ToString ();
147                                 return class_name;
148                         }
149                 }
150
151                 public virtual string Message {
152                         get {
153                                 if (message == null)
154                                         message = string.Format (Locale.GetText ("Exception of type '{0}' was thrown."),
155                                                 ClassName);
156
157                                 return message;
158                         }
159                 }
160                 
161                 [MonoTODO]
162                 protected event EventHandler<SafeSerializationEventArgs> SerializeObjectState {
163                         add {
164                         }
165                         remove {
166                         }
167                 }
168
169                 public virtual string Source {
170                         get {
171                                 if (source == null) {
172                                         StackTrace st = new StackTrace (this, true);
173                                         if (st.FrameCount > 0) {
174                                                 StackFrame sf = st.GetFrame (0);
175                                                 if (st != null) {
176                                                         MethodBase method = sf.GetMethod ();
177                                                         if (method != null) {
178                                                                 source = method.DeclaringType.Assembly.UnprotectedGetName ().Name;
179                                                         }
180                                                 }
181                                         }
182                                 }
183
184                                 // source can be null
185                                 return source;
186                         }
187
188                         set {
189                                 source = value;
190                         }
191                 }
192
193                 bool AddFrames (StringBuilder sb, string newline, string unknown, StackTrace st)
194                 {
195                         int i;
196                         for (i = 0; i < st.FrameCount; i++) {
197                                 StackFrame frame = st.GetFrame (i);
198                                 if (i == 0)
199                                         sb.AppendFormat ("  {0} ", Locale.GetText ("at"));
200                                 else
201                                         sb.Append (newline);
202
203                                 if (frame.GetMethod () == null) {
204                                         string internal_name = frame.GetInternalMethodName ();
205                                         if (internal_name != null)
206                                                 sb.Append (internal_name);
207                                         else
208                                                 sb.AppendFormat ("<0x{0:x5} + 0x{1:x5}> {2}", frame.GetMethodAddress (), frame.GetNativeOffset (), unknown);
209                                 } else {
210                                         GetFullNameForStackTrace (sb, frame.GetMethod ());
211
212                                         if (frame.GetILOffset () == -1) {
213                                                 sb.AppendFormat (" <0x{0:x5} + 0x{1:x5}> ", frame.GetMethodAddress (), frame.GetNativeOffset ());
214                                                 if (frame.GetMethodIndex () != 0xffffff)
215                                                         sb.AppendFormat ("{0} ", frame.GetMethodIndex ());
216                                         } else {
217                                                 sb.AppendFormat (" [0x{0:x5}] ", frame.GetILOffset ());
218                                         }
219
220                                         sb.AppendFormat ("in {0}:{1} ", frame.GetSecureFileName (),
221                                                                          frame.GetFileLineNumber ());
222                                 }
223                         }
224
225                         return i != 0;
226                 }
227
228                 public virtual string StackTrace {
229                         get {
230                                 if (stack_trace != null)
231                                         return stack_trace;
232
233                                 if (trace_ips == null)
234                                         /* Not thrown yet */
235                                         return null;
236
237                                 StringBuilder sb = new StringBuilder ();
238
239                                 string newline = String.Format ("{0}  {1} ", Environment.NewLine, Locale.GetText ("at"));
240                                 string unknown = Locale.GetText ("<unknown method>");
241
242                                 // Add traces captured using ExceptionDispatchInfo
243                                 if (captured_traces != null) {
244                                         foreach (var t in captured_traces) {
245                                                 if (!AddFrames (sb, newline, unknown, t))
246                                                         continue;
247
248                                                 sb.Append (Environment.NewLine);
249                                                 sb.Append ("--- End of stack trace from previous location where exception was thrown ---");
250                                                 sb.Append (Environment.NewLine);
251                                         }
252                                 }
253
254                                 StackTrace st = new StackTrace (this, 0, true, true);
255                                 AddFrames (sb, newline, unknown, st);
256
257                                 stack_trace = sb.ToString ();
258
259                                 return stack_trace;
260                         }
261                 }
262
263                 public MethodBase TargetSite {
264                         get {
265                                 StackTrace st = new StackTrace (this, true);
266                                 if (st.FrameCount > 0)
267                                         return st.GetFrame (0).GetMethod ();
268                                 
269                                 return null;
270                         }
271                 }
272
273                 public virtual IDictionary Data {
274                         get {
275                                 if (_data == null) {
276                                         // default to empty dictionary
277                                         _data = new Dictionary<object, object> ();
278                                 }
279                                 return _data;
280                         }
281                 }
282
283                 public virtual Exception GetBaseException ()
284                 {
285                         Exception inner = inner_exception;
286                                 
287                         while (inner != null)
288                         {
289                                 if (inner.InnerException != null)
290                                         inner = inner.InnerException;
291                                 else
292                                         return inner;
293                         }
294
295                         return this;
296                 }
297
298                 [SecurityPermission (SecurityAction.LinkDemand, SerializationFormatter = true)]
299                 public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
300                 {
301                         if (info == null)
302                                 throw new ArgumentNullException ("info");
303
304                         info.AddValue ("ClassName", ClassName);
305                         info.AddValue ("Message", message);
306                         info.AddValue ("InnerException", inner_exception);
307                         info.AddValue ("HelpURL", help_link);
308                         info.AddValue ("StackTraceString", StackTrace);
309                         info.AddValue ("RemoteStackTraceString", _remoteStackTraceString);
310                         info.AddValue ("RemoteStackIndex", remote_stack_index);
311                         info.AddValue ("HResult", hresult);
312                         info.AddValue ("Source", Source);
313                         info.AddValue ("ExceptionMethod", null);
314                         info.AddValue ("Data", _data, typeof (IDictionary));
315                 }
316
317                 public override string ToString ()
318                 {
319                         System.Text.StringBuilder result = new System.Text.StringBuilder (ClassName);
320                         result.Append (": ").Append (Message);
321
322                         if (null != _remoteStackTraceString)
323                                 result.Append (_remoteStackTraceString);
324                                 
325                         if (inner_exception != null) 
326                         {
327                                 result.Append (" ---> ").Append (inner_exception.ToString ());
328                                 result.Append (Environment.NewLine);
329                                 result.Append (Locale.GetText ("  --- End of inner exception stack trace ---"));
330                         }
331
332                         if (StackTrace != null)
333                                 result.Append (Environment.NewLine).Append (StackTrace);
334                         return result.ToString();
335                 }
336
337                 internal Exception FixRemotingException ()
338                 {
339                         string message = (0 == remote_stack_index) ?
340                                 Locale.GetText ("{0}{0}Server stack trace: {0}{1}{0}{0}Exception rethrown at [{2}]: {0}") :
341                                 Locale.GetText ("{1}{0}{0}Exception rethrown at [{2}]: {0}");
342                         string tmp = String.Format (message, Environment.NewLine, StackTrace, remote_stack_index);
343
344                         _remoteStackTraceString = tmp;
345                         remote_stack_index++;
346
347                         stack_trace = null;
348
349                         return this;
350                 }
351
352                 internal static void GetFullNameForStackTrace (StringBuilder sb, MethodBase mi)
353                 {
354                         var declaringType = mi.DeclaringType;
355                         if (declaringType.IsGenericType && !declaringType.IsGenericTypeDefinition)
356                                 declaringType = declaringType.GetGenericTypeDefinition ();
357
358                         // Get generic definition
359                         var bindingflags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
360                         foreach (var m in declaringType.GetMethods (bindingflags)) {
361                                 if (m.MetadataToken == mi.MetadataToken) {
362                                         mi = m;
363                                         break;
364                                 }
365                         }
366
367                         sb.Append (declaringType.ToString ());
368
369                         sb.Append (".");
370                         sb.Append (mi.Name);
371
372                         if (mi.IsGenericMethod) {
373                                 Type[] gen_params = mi.GetGenericArguments ();
374                                 sb.Append ("[");
375                                 for (int j = 0; j < gen_params.Length; j++) {
376                                         if (j > 0)
377                                                 sb.Append (",");
378                                         sb.Append (gen_params [j].Name);
379                                 }
380                                 sb.Append ("]");
381                         }
382
383                         ParameterInfo[] p = mi.GetParametersInternal ();
384
385                         sb.Append (" (");
386                         for (int i = 0; i < p.Length; ++i) {
387                                 if (i > 0)
388                                         sb.Append (", ");
389
390                                 Type pt = p[i].ParameterType;
391                                 if (pt.IsGenericType && ! pt.IsGenericTypeDefinition)
392                                         pt = pt.GetGenericTypeDefinition ();
393
394                                 if (pt.IsClass && !String.IsNullOrEmpty (pt.Namespace)) {
395                                         sb.Append (pt.Namespace);
396                                         sb.Append (".");
397                                 }
398                                 sb.Append (pt.Name);
399                                 if (p [i].Name != null) {
400                                         sb.Append (" ");
401                                         sb.Append (p [i].Name);
402                                 }
403                         }
404                         sb.Append (")");
405                 }
406
407                 // For ExceptionDispatchInfo
408                 internal void RestoreExceptionDispatchInfo (System.Runtime.ExceptionServices.ExceptionDispatchInfo exceptionDispatchInfo)
409                 {
410                         if (captured_traces != null) {
411                                 Array.Resize (ref captured_traces, captured_traces.Length + 1);
412                         } else {
413                                 captured_traces = new StackTrace [1];
414                         }
415                         captured_traces [captured_traces.Length - 1] = new StackTrace (this, 0, true, true);
416
417                         trace_ips = null;
418                 }
419
420                 //
421                 // The documentation states that this is available in 1.x,
422                 // but it was not available (MemberRefing this would fail)
423                 // and it states the signature is `override sealed', but the
424                 // correct value is `newslot' 
425                 //
426                 public new Type GetType ()
427                 {
428                         return base.GetType ();
429                 }
430
431                 internal enum ExceptionMessageKind
432                 {
433                         ThreadAbort = 1,
434                         ThreadInterrupted = 2,
435                         OutOfMemory = 3
436                 }
437
438                 internal static String GetMessageFromNativeResources (ExceptionMessageKind kind)
439                 {
440                         switch (kind) {
441                         case ExceptionMessageKind.ThreadAbort:
442                                 return "";
443                         case ExceptionMessageKind.ThreadInterrupted:
444                                 return "";
445                         case ExceptionMessageKind.OutOfMemory:
446                                 return "Out of memory";
447                         }
448                         return "";
449                 }
450         }
451 }