New test.
[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;
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         [MonoTODO ("Fix serialization compatibility with MS.NET")]
45         public class StackTrace {
46
47                 public const int METHODS_TO_SKIP = 0;
48
49                 private StackFrame[] frames;
50                 private bool debug_info;
51
52                 public StackTrace ()
53                 {
54                         init_frames (METHODS_TO_SKIP, false);
55                 }
56
57                 public StackTrace (bool needFileInfo)
58                 {
59                         init_frames (METHODS_TO_SKIP, needFileInfo);
60                 }
61
62                 public StackTrace (int skipFrames)
63                 {
64                         init_frames (skipFrames, false);
65                 }
66
67                 public StackTrace (int skipFrames, bool needFileInfo)
68                 {
69                         init_frames (skipFrames, needFileInfo);
70                 }
71
72                 void init_frames (int skipFrames, bool needFileInfo)
73                 {
74                         if (skipFrames < 0)
75                                 throw new ArgumentOutOfRangeException ("< 0", "skipFrames");
76
77                         StackFrame sf;
78                         ArrayList al = new ArrayList ();
79
80                         skipFrames += 2;
81                         
82                         while ((sf = new StackFrame (skipFrames, needFileInfo)) != null &&
83                                sf.GetMethod () != null) {
84                                 
85                                 al.Add (sf);
86                                 skipFrames++;
87                         };
88
89                         debug_info = needFileInfo;
90                         frames = (StackFrame [])al.ToArray (typeof (StackFrame));       
91                 }
92                 
93                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
94                 extern static StackFrame [] get_trace (Exception e, int skipFrames, bool needFileInfo);
95
96                 public StackTrace (Exception e)
97                         : this (e, METHODS_TO_SKIP, false)
98                 {
99                 }
100
101                 public StackTrace (Exception e, bool needFileInfo)
102                         : this (e, METHODS_TO_SKIP, needFileInfo)
103                 {
104                 }
105
106                 public StackTrace (Exception e, int skipFrames)
107                         : this (e, skipFrames, false)
108                 {
109                 }
110
111                 public StackTrace (Exception e, int skipFrames, bool needFileInfo)
112                         : this (e, skipFrames, needFileInfo, false)
113                 {
114                 }
115
116                 internal StackTrace (Exception e, int skipFrames, bool needFileInfo, bool returnNativeFrames)
117                 {
118                         if (e == null)
119                                 throw new ArgumentNullException ("e");
120                         if (skipFrames < 0)
121                                 throw new ArgumentOutOfRangeException ("< 0", "skipFrames");
122
123                         frames = get_trace (e, skipFrames, needFileInfo);
124
125                         if (!returnNativeFrames) {
126                                 bool resize = false;
127                                 for (int i = 0; i < frames.Length; ++i)
128                                         if (frames [i].GetMethod () == null)
129                                                 resize = true;
130
131                                 if (resize) {
132                                         ArrayList al = new ArrayList ();
133
134                                         for (int i = 0; i < frames.Length; ++i)
135                                                 if (frames [i].GetMethod () != null)
136                                                         al.Add (frames [i]);
137
138                                         frames = (StackFrame [])al.ToArray (typeof (StackFrame));
139                                 }
140                         }
141                 }
142
143 #if ONLY_1_1
144                 [ReflectionPermission (SecurityAction.Demand, TypeInformation = true)]
145 #endif
146                 public StackTrace (StackFrame frame)
147                 {
148                         this.frames = new StackFrame [1];
149                         this.frames [0] = frame;
150                 }
151
152 #if ONLY_1_1
153                 [ReflectionPermission (SecurityAction.Demand, TypeInformation = true)]
154 #endif
155                 [MonoTODO]
156                 public StackTrace (Thread targetThread, bool needFileInfo)
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 #if NET_2_0
177                 [ComVisibleAttribute (false)]
178                 public virtual
179 #else
180                 // used for CAS implementation (before Fx 2.0)
181                 internal
182 #endif
183                 StackFrame[] GetFrames ()
184                 {
185                         return frames;
186                 }
187
188                 public override string ToString ()
189                 {
190                         string newline = String.Format ("{0}   {1} ", Environment.NewLine, Locale.GetText ("at"));
191                         string unknown = Locale.GetText ("<unknown method>");
192                         string debuginfo = Locale.GetText (" in {0}:line {1}");
193                         StringBuilder sb = new StringBuilder ();
194                         for (int i = 0; i < FrameCount; i++) {
195                                 StackFrame frame = GetFrame (i);
196                                 sb.Append (newline);
197                                 MethodBase method = frame.GetMethod ();
198                                 if (method != null) {
199                                         // Method information available
200                                         sb.AppendFormat ("{0}.{1} ()", method.DeclaringType.FullName, method.Name);
201                                 }
202                                 else {
203                                         // Method information not available
204                                         sb.Append (unknown);
205                                 }
206
207                                 if (debug_info) {
208                                         // we were asked for debugging informations
209                                         try {
210                                                 // but that doesn't mean we have the debug information available
211                                                 string fname = frame.GetFileName ();
212                                                 if ((fname != null) && (fname.Length > 0))
213                                                         sb.AppendFormat (debuginfo, fname, frame.GetFileLineNumber ());
214                                         }
215                                         catch (SecurityException) {
216                                                 // don't leak information (about the filename) if the security 
217                                                 // manager doesn't allow it (but don't loop on this exception)
218                                                 debug_info = false;
219                                         }
220                                 }
221                         }
222                         return sb.ToString ();
223                 }
224         }
225 }