Merge pull request #1505 from esdrubal/tzifloatingrule
[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                 internal void SetMessage (string s)
128                 {
129                         message = s;
130                 }
131
132                 internal void SetStackTrace (string s)
133                 {
134                         stack_trace = s;
135                 }
136
137                 string ClassName {
138                         get {
139                                 if (class_name == null)
140                                         class_name = GetType ().ToString ();
141                                 return class_name;
142                         }
143                 }
144
145                 public virtual string Message {
146                         get {
147                                 if (message == null)
148                                         message = string.Format (Locale.GetText ("Exception of type '{0}' was thrown."),
149                                                 ClassName);
150
151                                 return message;
152                         }
153                 }
154                 
155                 [MonoTODO]
156                 protected event EventHandler<SafeSerializationEventArgs> SerializeObjectState {
157                         add {
158                         }
159                         remove {
160                         }
161                 }
162
163                 public virtual string Source {
164                         get {
165                                 if (source == null) {
166                                         StackTrace st = new StackTrace (this, true);
167                                         if (st.FrameCount > 0) {
168                                                 StackFrame sf = st.GetFrame (0);
169                                                 if (st != null) {
170                                                         MethodBase method = sf.GetMethod ();
171                                                         if (method != null) {
172                                                                 source = method.DeclaringType.Assembly.UnprotectedGetName ().Name;
173                                                         }
174                                                 }
175                                         }
176                                 }
177
178                                 // source can be null
179                                 return source;
180                         }
181
182                         set {
183                                 source = value;
184                         }
185                 }
186
187                 bool AddFrames (StringBuilder sb, string newline, string unknown, StackTrace st)
188                 {
189                         int i;
190                         for (i = 0; i < st.FrameCount; i++) {
191                                 StackFrame frame = st.GetFrame (i);
192                                 if (i == 0)
193                                         sb.AppendFormat ("  {0} ", Locale.GetText ("at"));
194                                 else
195                                         sb.Append (newline);
196
197                                 if (frame.GetMethod () == null) {
198                                         string internal_name = frame.GetInternalMethodName ();
199                                         if (internal_name != null)
200                                                 sb.Append (internal_name);
201                                         else
202                                                 sb.AppendFormat ("<0x{0:x5} + 0x{1:x5}> {2}", frame.GetMethodAddress (), frame.GetNativeOffset (), unknown);
203                                 } else {
204                                         GetFullNameForStackTrace (sb, frame.GetMethod ());
205
206                                         if (frame.GetILOffset () == -1)
207                                                 sb.AppendFormat ("<0x{0:x5} + 0x{1:x5}> ", frame.GetMethodAddress (), frame.GetNativeOffset ());
208                                         else
209                                                 sb.AppendFormat (" [0x{0:x5}] ", frame.GetILOffset ());
210
211                                         sb.AppendFormat ("in {0}:{1} ", frame.GetSecureFileName (),
212                                                                          frame.GetFileLineNumber ());
213                                 }
214                         }
215
216                         return i != 0;
217                 }
218
219                 public virtual string StackTrace {
220                         get {
221                                 if (stack_trace != null)
222                                         return stack_trace;
223
224                                 if (trace_ips == null)
225                                         /* Not thrown yet */
226                                         return null;
227
228                                 StringBuilder sb = new StringBuilder ();
229
230                                 string newline = String.Format ("{0}  {1} ", Environment.NewLine, Locale.GetText ("at"));
231                                 string unknown = Locale.GetText ("<unknown method>");
232
233                                 // Add traces captured using ExceptionDispatchInfo
234                                 if (captured_traces != null) {
235                                         foreach (var t in captured_traces) {
236                                                 if (!AddFrames (sb, newline, unknown, t))
237                                                         continue;
238
239                                                 sb.Append (Environment.NewLine);
240                                                 sb.Append ("--- End of stack trace from previous location where exception was thrown ---");
241                                                 sb.Append (Environment.NewLine);
242                                         }
243                                 }
244
245                                 StackTrace st = new StackTrace (this, 0, true, true);
246                                 AddFrames (sb, newline, unknown, st);
247
248                                 stack_trace = sb.ToString ();
249
250                                 return stack_trace;
251                         }
252                 }
253
254                 public MethodBase TargetSite {
255                         get {
256                                 StackTrace st = new StackTrace (this, true);
257                                 if (st.FrameCount > 0)
258                                         return st.GetFrame (0).GetMethod ();
259                                 
260                                 return null;
261                         }
262                 }
263
264                 public virtual IDictionary Data {
265                         get {
266                                 if (_data == null) {
267                                         // default to empty dictionary
268                                         _data = new Dictionary<object, object> ();
269                                 }
270                                 return _data;
271                         }
272                 }
273
274                 public virtual Exception GetBaseException ()
275                 {
276                         Exception inner = inner_exception;
277                                 
278                         while (inner != null)
279                         {
280                                 if (inner.InnerException != null)
281                                         inner = inner.InnerException;
282                                 else
283                                         return inner;
284                         }
285
286                         return this;
287                 }
288
289                 [SecurityPermission (SecurityAction.LinkDemand, SerializationFormatter = true)]
290                 public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
291                 {
292                         if (info == null)
293                                 throw new ArgumentNullException ("info");
294
295                         info.AddValue ("ClassName", ClassName);
296                         info.AddValue ("Message", message);
297                         info.AddValue ("InnerException", inner_exception);
298                         info.AddValue ("HelpURL", help_link);
299                         info.AddValue ("StackTraceString", StackTrace);
300                         info.AddValue ("RemoteStackTraceString", _remoteStackTraceString);
301                         info.AddValue ("RemoteStackIndex", remote_stack_index);
302                         info.AddValue ("HResult", hresult);
303                         info.AddValue ("Source", Source);
304                         info.AddValue ("ExceptionMethod", null);
305                         info.AddValue ("Data", _data, typeof (IDictionary));
306                 }
307
308                 public override string ToString ()
309                 {
310                         System.Text.StringBuilder result = new System.Text.StringBuilder (ClassName);
311                         result.Append (": ").Append (Message);
312
313                         if (null != _remoteStackTraceString)
314                                 result.Append (_remoteStackTraceString);
315                                 
316                         if (inner_exception != null) 
317                         {
318                                 result.Append (" ---> ").Append (inner_exception.ToString ());
319                                 result.Append (Environment.NewLine);
320                                 result.Append (Locale.GetText ("  --- End of inner exception stack trace ---"));
321                         }
322
323                         if (StackTrace != null)
324                                 result.Append (Environment.NewLine).Append (StackTrace);
325                         return result.ToString();
326                 }
327
328                 internal Exception FixRemotingException ()
329                 {
330                         string message = (0 == remote_stack_index) ?
331                                 Locale.GetText ("{0}{0}Server stack trace: {0}{1}{0}{0}Exception rethrown at [{2}]: {0}") :
332                                 Locale.GetText ("{1}{0}{0}Exception rethrown at [{2}]: {0}");
333                         string tmp = String.Format (message, Environment.NewLine, StackTrace, remote_stack_index);
334
335                         _remoteStackTraceString = tmp;
336                         remote_stack_index++;
337
338                         stack_trace = null;
339
340                         return this;
341                 }
342
343                 internal void GetFullNameForStackTrace (StringBuilder sb, MethodBase mi)
344                 {
345                         ParameterInfo[] p = mi.GetParametersInternal ();
346                         sb.Append (mi.DeclaringType.ToString ());
347                         sb.Append (".");
348                         sb.Append (mi.Name);
349
350                         if (mi.IsGenericMethod) {
351                                 Type[] gen_params = mi.GetGenericArguments ();
352                                 sb.Append ("[");
353                                 for (int j = 0; j < gen_params.Length; j++) {
354                                         if (j > 0)
355                                                 sb.Append (",");
356                                         sb.Append (gen_params [j].Name);
357                                 }
358                                 sb.Append ("]");
359                         }
360
361                         sb.Append (" (");
362                         for (int i = 0; i < p.Length; ++i) {
363                                 if (i > 0)
364                                         sb.Append (", ");
365                                 Type pt = p[i].ParameterType;
366                                 if (pt.IsClass && !String.IsNullOrEmpty (pt.Namespace)) {
367                                         sb.Append (pt.Namespace);
368                                         sb.Append (".");
369                                 }
370                                 sb.Append (pt.Name);
371                                 if (p [i].Name != null) {
372                                         sb.Append (" ");
373                                         sb.Append (p [i].Name);
374                                 }
375                         }
376                         sb.Append (")");
377                 }
378
379                 // For ExceptionDispatchInfo
380                 internal void CaptureTrace ()
381                 {
382                         if (captured_traces != null) {
383                                 Array.Resize (ref captured_traces, captured_traces.Length + 1);
384                         } else {
385                                 captured_traces = new StackTrace [1];
386                         }
387                         captured_traces [captured_traces.Length - 1] = new StackTrace (this, 0, true, true);
388
389                         trace_ips = null;
390                 }
391
392                 //
393                 // The documentation states that this is available in 1.x,
394                 // but it was not available (MemberRefing this would fail)
395                 // and it states the signature is `override sealed', but the
396                 // correct value is `newslot' 
397                 //
398                 public new Type GetType ()
399                 {
400                         return base.GetType ();
401                 }
402         }
403 }