Merge pull request #1504 from madrang/SafeHandle.SetInvalidRelease
[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                 [Obsolete]
152                 public StackTrace (Thread targetThread, bool needFileInfo)
153                 {
154                         if (targetThread == Thread.CurrentThread){
155                                 init_frames (METHODS_TO_SKIP, needFileInfo);
156                                 return;
157                         }
158                         
159                         throw new NotImplementedException ();
160                 }
161
162                 public virtual int FrameCount {
163                         get {
164                                 return (frames == null) ? 0 : frames.Length;
165                         }
166                 }
167
168                 public virtual StackFrame GetFrame (int index)
169                 {
170                         if ((index < 0) || (index >= FrameCount)) {
171                                 return null;
172                         }
173
174                         return frames [index];
175                 }
176
177                 [ComVisibleAttribute (false)]
178                 public virtual StackFrame[] GetFrames ()
179                 {
180                         return frames;
181                 }
182
183                 public override string ToString ()
184                 {
185                         string newline = String.Format ("{0}   {1} ", Environment.NewLine, Locale.GetText ("at"));
186                         string unknown = Locale.GetText ("<unknown method>");
187                         string debuginfo = Locale.GetText (" in {0}:line {1}");
188                         StringBuilder sb = new StringBuilder ();
189                         for (int i = 0; i < FrameCount; i++) {
190                                 StackFrame frame = GetFrame (i);
191                                 if (i > 0)
192                                         sb.Append (newline);
193                                 else
194                                         sb.AppendFormat ("   {0} ", Locale.GetText ("at"));
195                                 MethodBase method = frame.GetMethod ();
196                                 if (method != null) {
197                                         // Method information available
198                                         sb.AppendFormat ("{0}.{1}", method.DeclaringType.FullName, method.Name);
199                                         /* Append parameter information */
200                                         sb.Append ("(");
201                                         ParameterInfo[] p = method.GetParametersInternal ();
202                                         for (int j = 0; j < p.Length; ++j) {
203                                                 if (j > 0)
204                                                         sb.Append (", ");
205                                                 Type pt = p[j].ParameterType;
206                                                 bool byref = pt.IsByRef;
207                                                 if (byref)
208                                                         pt = pt.GetElementType ();
209                                                 if (pt.IsClass && pt.Namespace != String.Empty) {
210                                                         sb.Append (pt.Namespace);
211                                                         sb.Append (".");
212                                                 }
213                                                 sb.Append (pt.Name);
214                                                 if (byref)
215                                                         sb.Append (" ByRef");
216                                                 sb.AppendFormat (" {0}", p [j].Name);
217                                         }
218                                         sb.Append (")");
219                                 }
220                                 else {
221                                         // Method information not available
222                                         sb.Append (unknown);
223                                 }
224
225                                 if (debug_info) {
226                                         // we were asked for debugging informations
227                                         // but that doesn't mean we have the debug information available
228                                         string fname = frame.GetSecureFileName ();
229                                         if (fname != "<filename unknown>")
230                                                 sb.AppendFormat (debuginfo, fname, frame.GetFileLineNumber ());
231                                 }
232                         }
233                         return sb.ToString ();
234                 }
235         }
236 }