BindingFlags.Public needed here as Exception.HResult is now public in .NET 4.5. This...
[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
41 namespace System.Diagnostics {
42
43         [Serializable]
44         [ComVisible (true)]
45         [MonoTODO ("Serialized objects are not compatible with .NET")]
46         public class StackTrace {
47
48                 public const int METHODS_TO_SKIP = 0;
49
50                 private StackFrame[] frames;
51                 private bool debug_info;
52
53                 public StackTrace ()
54                 {
55                         init_frames (METHODS_TO_SKIP, false);
56                 }
57
58                 public StackTrace (bool fNeedFileInfo)
59                 {
60                         init_frames (METHODS_TO_SKIP, fNeedFileInfo);
61                 }
62
63                 public StackTrace (int skipFrames)
64                 {
65                         init_frames (skipFrames, false);
66                 }
67
68                 public StackTrace (int skipFrames, bool fNeedFileInfo)
69                 {
70                         init_frames (skipFrames, fNeedFileInfo);
71                 }
72
73                 void init_frames (int skipFrames, bool fNeedFileInfo)
74                 {
75                         if (skipFrames < 0)
76                                 throw new ArgumentOutOfRangeException ("< 0", "skipFrames");
77
78                         StackFrame sf;
79                         var l = new List<StackFrame> ();
80
81                         skipFrames += 2;
82                         
83                         while ((sf = new StackFrame (skipFrames, fNeedFileInfo)) != null &&
84                                sf.GetMethod () != null) {
85                                 
86                                 l.Add (sf);
87                                 skipFrames++;
88                         };
89
90                         debug_info = fNeedFileInfo;
91                         frames = l.ToArray ();
92                 }
93                 
94                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
95                 extern static StackFrame [] get_trace (Exception e, int skipFrames, bool fNeedFileInfo);
96
97                 public StackTrace (Exception e)
98                         : this (e, METHODS_TO_SKIP, false)
99                 {
100                 }
101
102                 public StackTrace (Exception e, bool fNeedFileInfo)
103                         : this (e, METHODS_TO_SKIP, fNeedFileInfo)
104                 {
105                 }
106
107                 public StackTrace (Exception e, int skipFrames)
108                         : this (e, skipFrames, false)
109                 {
110                 }
111
112                 public StackTrace (Exception e, int skipFrames, bool fNeedFileInfo)
113                         : this (e, skipFrames, fNeedFileInfo, false)
114                 {
115                 }
116
117                 internal StackTrace (Exception e, int skipFrames, bool fNeedFileInfo, bool returnNativeFrames)
118                 {
119                         if (e == null)
120                                 throw new ArgumentNullException ("e");
121                         if (skipFrames < 0)
122                                 throw new ArgumentOutOfRangeException ("< 0", "skipFrames");
123
124                         frames = get_trace (e, skipFrames, fNeedFileInfo);
125
126                         if (!returnNativeFrames) {
127                                 bool resize = false;
128                                 for (int i = 0; i < frames.Length; ++i)
129                                         if (frames [i].GetMethod () == null)
130                                                 resize = true;
131
132                                 if (resize) {
133                                         var l = new List<StackFrame> ();
134
135                                         for (int i = 0; i < frames.Length; ++i)
136                                                 if (frames [i].GetMethod () != null)
137                                                         l.Add (frames [i]);
138
139                                         frames = l.ToArray ();
140                                 }
141                         }
142                 }
143
144                 public StackTrace (StackFrame frame)
145                 {
146                         this.frames = new StackFrame [1];
147                         this.frames [0] = frame;
148                 }
149
150                 [MonoLimitation ("Not possible to create StackTraces from other threads")]
151                 public StackTrace (Thread targetThread, bool needFileInfo)
152                 {
153                         if (targetThread == Thread.CurrentThread){
154                                 init_frames (METHODS_TO_SKIP, needFileInfo);
155                                 return;
156                         }
157                         
158                         throw new NotImplementedException ();
159                 }
160
161                 public virtual int FrameCount {
162                         get {
163                                 return (frames == null) ? 0 : frames.Length;
164                         }
165                 }
166
167                 public virtual StackFrame GetFrame (int index)
168                 {
169                         if ((index < 0) || (index >= FrameCount)) {
170                                 return null;
171                         }
172
173                         return frames [index];
174                 }
175
176                 [ComVisibleAttribute (false)]
177                 public virtual StackFrame[] GetFrames ()
178                 {
179                         return frames;
180                 }
181
182                 public override string ToString ()
183                 {
184                         string newline = String.Format ("{0}   {1} ", Environment.NewLine, Locale.GetText ("at"));
185                         string unknown = Locale.GetText ("<unknown method>");
186                         string debuginfo = Locale.GetText (" in {0}:line {1}");
187                         StringBuilder sb = new StringBuilder ();
188                         for (int i = 0; i < FrameCount; i++) {
189                                 StackFrame frame = GetFrame (i);
190                                 if (i > 0)
191                                         sb.Append (newline);
192                                 else
193                                         sb.AppendFormat ("   {0} ", Locale.GetText ("at"));
194                                 MethodBase method = frame.GetMethod ();
195                                 if (method != null) {
196                                         // Method information available
197                                         sb.AppendFormat ("{0}.{1}", method.DeclaringType.FullName, method.Name);
198                                         /* Append parameter information */
199                                         sb.Append ("(");
200                                         ParameterInfo[] p = method.GetParameters ();
201                                         for (int j = 0; j < p.Length; ++j) {
202                                                 if (j > 0)
203                                                         sb.Append (", ");
204                                                 Type pt = p[j].ParameterType;
205                                                 bool byref = pt.IsByRef;
206                                                 if (byref)
207                                                         pt = pt.GetElementType ();
208                                                 if (pt.IsClass && pt.Namespace != String.Empty) {
209                                                         sb.Append (pt.Namespace);
210                                                         sb.Append (".");
211                                                 }
212                                                 sb.Append (pt.Name);
213                                                 if (byref)
214                                                         sb.Append (" ByRef");
215                                                 sb.AppendFormat (" {0}", p [j].Name);
216                                         }
217                                         sb.Append (")");
218                                 }
219                                 else {
220                                         // Method information not available
221                                         sb.Append (unknown);
222                                 }
223
224                                 if (debug_info) {
225                                         // we were asked for debugging informations
226                                         // but that doesn't mean we have the debug information available
227                                         string fname = frame.GetSecureFileName ();
228                                         if (fname != "<filename unknown>")
229                                                 sb.AppendFormat (debuginfo, fname, frame.GetFileLineNumber ());
230                                 }
231                         }
232                         return sb.ToString ();
233                 }
234         }
235 }