This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[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 //
10
11 //
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 using System;
35 using System.Reflection;
36 using System.Threading;
37 using System.Runtime.CompilerServices;
38 using System.Collections;
39
40 namespace System.Diagnostics {
41         /// <summary>
42         ///   Stack trace.
43         ///   TODO: more information.
44         /// </summary>
45         [Serializable]
46         [MonoTODO ("Fix serialization compatibility with MS.NET")]
47         public class StackTrace {
48                 /// <value>
49                 ///   Uses a constant to define the number of methods that are
50                 ///   to be omitted from the stack trace.
51                 /// </value>
52                 public const int METHODS_TO_SKIP = 0;
53                 
54                 /// <value>
55                 ///   Frames. First frame is the last stack frame pushed.
56                 /// </value>
57                 private StackFrame[] frames;
58
59                 /// <summary>
60                 ///   Initializes a new instance of the StackTrace class.
61                 /// </summary>
62                 [MonoTODO]
63                 public StackTrace() {
64                         init_frames (METHODS_TO_SKIP, false);
65                 }
66                 
67                 /// <summary>
68                 ///   Initializes a new instance of the StackTrace class.
69                 /// </summary>
70                 /// <param name="needFileInfo">
71                 ///   TODO:
72                 /// </param>
73                 public StackTrace(bool needFileInfo) {
74                         init_frames (METHODS_TO_SKIP, needFileInfo);
75                 }
76
77                 /// <summary>
78                 ///   Initializes a new instance of the StackTrace class
79                 ///   from the current location, in a caller's frame.
80                 /// </summary>
81                 /// <param name="skipFrames">
82                 ///   The number of frames up the stack to start the trace
83                 ///   from.
84                 /// </param>
85                 public StackTrace(int skipFrames) {
86                         init_frames (skipFrames, false);
87                 }
88
89                 /// <summary>
90                 ///   Initializes a new instance of the StackTrace class
91                 ///   from the current location, in a caller's frame.
92                 /// </summary>
93                 /// <param name="skipFrames">
94                 ///   The number of frames up the stack to start the trace
95                 ///   from.
96                 /// </param>
97                 /// <param name="needFileInfo">
98                 ///   TODO:
99                 /// </param>
100                 public StackTrace(int skipFrames, bool needFileInfo) {
101                         init_frames (skipFrames, needFileInfo);
102                 }
103
104                 void init_frames (int skipFrames, bool needFileInfo)
105                 {
106                         StackFrame sf;
107                         ArrayList al = new ArrayList ();
108
109                         skipFrames += 2;
110                         
111                         while ((sf = new StackFrame (skipFrames, needFileInfo)) != null &&
112                                sf.GetMethod () != null) {
113                                 
114                                 al.Add (sf);
115                                 skipFrames++;
116                         };
117
118                         frames = (StackFrame [])al.ToArray (typeof (StackFrame));       
119                 }
120                 
121                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
122                 extern static StackFrame [] get_trace (Exception e, int skipFrames, bool needFileInfo);
123
124                 /// <summary>
125                 ///   Initializes a new instance of the StackTrace class.
126                 /// </summary>
127                 /// <param name="e">
128                 ///   TODO:
129                 /// </param>
130                 public StackTrace(Exception e) {
131                         frames = get_trace (e, METHODS_TO_SKIP, false);
132                 }
133                                 
134                 /// <summary>
135                 ///   Initializes a new instance of the StackTrace class,
136                 ///   using the provided exception object. The resulting stack
137                 ///   trace describes the stack at the time of the exception.
138                 /// </summary>
139                 /// <param name="e">
140                 ///   TODO:
141                 /// </param>
142                 /// <param name="needFileInfo">
143                 ///   TODO:
144                 /// </param>
145                 public StackTrace(Exception e, bool needFileInfo) {
146                         frames = get_trace (e, METHODS_TO_SKIP, needFileInfo);
147                 }
148                 
149                 /// <summary>
150                 ///   Initializes a new instance of the StackTrace class,
151                 ///   using the provided exception object. The resulting stack
152                 ///   trace describes the stack at the time of the exception.
153                 /// </summary>
154                 /// <param name="e">
155                 ///   Exception.
156                 /// </param>
157                 /// <param name="skipFrames">
158                 ///   The number of frames up the stack to start the trace
159                 ///   from.
160                 /// </param>
161                 public StackTrace(Exception e, int skipFrames) {
162                         frames = get_trace (e, skipFrames, false);
163                 }
164                 
165                 /// <summary>
166                 ///   Initializes a new instance of the StackTrace class,
167                 ///   using the provided exception object. The resulting stack
168                 ///   trace describes the stack at the time of the exception.
169                 /// </summary>
170                 /// <param name="e">
171                 ///   Exception.
172                 /// </param>
173                 /// <param name="skipFrames">
174                 ///   The number of frames up the stack to start the trace
175                 ///   from.
176                 /// </param>
177                 /// <param name="needFileInfo">
178                 ///   TODO:
179                 /// </param>
180                 public StackTrace(Exception e, int skipFrames, bool needFileInfo) {
181                         frames = get_trace (e, skipFrames, needFileInfo);
182                 }
183                               
184                 /// <summary>
185                 ///   Initializes a new instance of the StackTrace class
186                 ///   containing a single frame.
187                 /// </summary>
188                 /// <param name="frame">
189                 ///   The frame that the StackTrace object should contain.
190                 /// </param>
191                 public StackTrace(StackFrame frame) {
192                         this.frames = new StackFrame[1];
193                         this.frames[0] = frame;
194                 }
195                                
196                 /// <summary>
197                 ///   Initializes a new instance of the StackTrace class.
198                 /// </summary>
199                 /// <param name="targetThread">
200                 ///   TODO:
201                 /// </param>
202                 /// <param name="needFileInfo">
203                 ///   TODO:
204                 /// </param>
205                 [MonoTODO]
206                 public StackTrace(Thread targetThread, bool needFileInfo) {
207                         throw new NotImplementedException();
208                 }
209                
210                 /// <summary>
211                 ///   Holds the number of frames in the stack trace.
212                 /// </summary>
213                 public virtual int FrameCount {
214                         get {
215                                 return (frames == null) ? 0 : frames.Length;
216                         }
217                 }             
218                               
219                 /// <summary>
220                 ///   Gets the specified stack frame.
221                 /// </summary>
222                 /// <param name="index">
223                 ///   The index of the stack frame requested.
224                 /// </param>
225                 /// <returns>
226                 ///   The specified stack frame. Returns <code>null</code> if
227                 ///   frame with specified index does not exist in this stack
228                 ///   trace.
229                 /// </returns>
230                 /// <remarks>
231                 ///   Stack frames are numbered starting at zero, which is the
232                 ///   last stack frame pushed.
233                 /// </remarks>
234                 public virtual StackFrame GetFrame(int index) {
235                         if ((index < 0) || (index >= FrameCount)) {
236                                 return null;
237                         }
238                         
239                         return frames[index];
240                 }              
241                 
242                 /// <summary>
243                 ///   Builds a readable representation of the stack trace.
244                 /// </summary>
245                 /// <returns>
246                 ///   A readable representation of the stack trace.
247                 /// </returns>
248                 public override string ToString() {
249                         string result = "";
250                         for (int i = 0; i < FrameCount; i++) {
251                                 StackFrame frame = GetFrame(i);
252                                 result += "\n\tat " + FrameToString(frame);
253                         }
254                         
255                         return result;
256                 }
257
258                 //
259                 // These are not on the Framework
260                 //
261 #if false
262                 
263                 public override bool Equals(Object obj) {
264                         if ((obj == null) || (!(obj is StackTrace))) {
265                                 return false;
266                         }
267                         
268                         StackTrace rhs = (StackTrace) obj;
269                         
270                         if (FrameCount != rhs.FrameCount) {
271                                 return false;
272                         }
273                         
274                         for (int i = 0; i < FrameCount; i++) {
275                                 if (!GetFrame(i).Equals(rhs.GetFrame(i))) {
276                                         return false;
277                                 }
278                         }
279                         
280                         return true;
281                 }
282                 
283                 public override int GetHashCode() {
284                         return FrameCount;
285                 }
286 #endif
287                 
288                 /// <summary>
289                 ///   Converts single stack frame to string to be used in
290                 ///   ToString method.
291                 /// </summary>
292                 /// <param name="frame">
293                 ///   Frame to convert.
294                 /// </param>
295                 /// <returns>
296                 ///   A readable representation of stack frame for using
297                 ///   ToString.
298                 /// </returns>
299                 private static String FrameToString(StackFrame frame) {
300                         MethodBase method = frame.GetMethod();
301                         if (method != null) {
302                                 // Method information available
303                                 return  method.DeclaringType.FullName
304                                         + "." + method.Name + "()";
305                         } else {
306                                 // Method information not available
307                                 return "<unknown method>";
308                         }
309                 }
310         }
311 }