2 // System.Diagnostics.StackFrame.cs
5 // Alexander Klyubin (klyubin@aqris.com)
6 // Dietmar Maurer (dietmar@ximian.com)
9 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
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:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
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.
32 using System.Reflection;
33 using System.Runtime.CompilerServices;
34 using System.Security;
35 using System.Security.Permissions;
38 namespace System.Diagnostics {
44 [MonoTODO ("Fix serialization compatibility with MS.NET")]
45 public class StackFrame {
47 /// Constant returned when the native or IL offset is unknown.
49 public const int OFFSET_UNKNOWN = -1;
52 /// Offset from the start of the IL code for the method
55 private int ilOffset = OFFSET_UNKNOWN;
58 /// Offset from the start of the native code for the method
61 private int nativeOffset = OFFSET_UNKNOWN;
64 /// Method associated with this stack frame.
66 private MethodBase methodBase;
71 private string fileName;
76 private int lineNumber;
81 private int columnNumber;
83 [MethodImplAttribute(MethodImplOptions.InternalCall)]
84 extern static bool get_frame_info (int skip, bool needFileInfo, out MethodBase method,
85 out int iloffset, out int native_offset,
86 out string file, out int line, out int column);
89 /// Initializes a new StackFrame object corresponding to the
90 /// active stack frame.
93 get_frame_info (2, false, out methodBase, out ilOffset,
94 out nativeOffset, out fileName, out lineNumber,
99 /// Initializes a new StackFrame object corresponding to the
100 /// active stack frame.
102 /// <param name="needFileInfo">
105 public StackFrame (bool needFileInfo)
107 get_frame_info (2, needFileInfo, out methodBase, out ilOffset,
108 out nativeOffset, out fileName, out lineNumber,
113 /// Initializes a new StackFrame object corresponding to the
114 /// active stack frame.
116 /// <param name="skipFrames">
117 /// The number of frames up the stack to skip.
119 public StackFrame(int skipFrames) {
120 get_frame_info (skipFrames + 2, false, out methodBase, out ilOffset,
121 out nativeOffset, out fileName, out lineNumber,
126 /// Initializes a new StackFrame object corresponding to the
127 /// active stack frame.
129 /// <param name="skipFrames">
130 /// The number of frames up the stack to skip.
132 /// <param name="needFileInfo">
135 public StackFrame(int skipFrames, bool needFileInfo) {
136 get_frame_info (skipFrames + 2, needFileInfo, out methodBase, out ilOffset,
137 out nativeOffset, out fileName, out lineNumber,
142 /// Constructs a fake stack frame that just contains the
143 /// given file name and line number. Use this constructor
144 /// when you do not want to use the debugger's line mapping
147 /// <param name="fileName">
148 /// The given file name.
150 /// <param name="lineNumber">
151 /// The line number in the specified file.
153 // LAMESPEC: According to the MSDN docs, this creates a
154 // fake stack frame. But MS fills out the frame info as well
155 public StackFrame(string fileName, int lineNumber) {
156 get_frame_info (2, false, out methodBase, out ilOffset,
157 out nativeOffset, out fileName, out lineNumber,
159 this.fileName = fileName;
160 this.lineNumber = lineNumber;
161 this.columnNumber = 0;
165 /// Constructs a fake stack frame that just contains the
166 /// given file name and line number. Use this constructor
167 /// when you do not want to use the debugger's line mapping
170 /// <param name="fileName">
171 /// The given file name.
173 /// <param name="lineNumber">
174 /// The line number in the specified file.
176 /// <param name="colNumber">
177 /// The column number in the specified file.
179 // LAMESPEC: According to the MSDN docs, this creates a
180 // fake stack frame. But MS fills out the frame info as well
181 public StackFrame(string fileName,
184 get_frame_info (2, false, out methodBase, out ilOffset,
185 out nativeOffset, out fileName, out lineNumber,
187 this.fileName = fileName;
188 this.lineNumber = lineNumber;
189 this.columnNumber = colNumber;
194 /// Gets the line number in the file containing the code
195 /// being executed. This information is typically extracted
196 /// from the debugging symbols for the executable.
199 /// The file line number or zero if it cannot be determined.
201 public virtual int GetFileLineNumber()
207 /// Gets the column number in the file containing the code
208 /// being executed. This information is typically extracted
209 /// from the debugging symbols for the executable.
212 /// The file column number or zero if it cannot be determined.
214 public virtual int GetFileColumnNumber()
220 /// Gets the file name containing the code being executed.
221 /// This information is typically extracted from the
222 /// debugging symbols for the executable.
225 /// The file name or null if it cannot be determined.
227 public virtual string GetFileName()
229 if (SecurityManager.SecurityEnabled && (fileName != null) && (fileName.Length > 0)) {
230 string fn = Path.GetFullPath (fileName);
231 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, fn).Demand ();
237 /// Gets the offset from the start of the IL code for the
238 /// method being executed. This offset may be approximate
239 /// depending on whether the JIT compiler is generating
240 /// debugging code or not.
243 /// The offset from the start of the IL code for the method
246 public virtual int GetILOffset()
252 /// Gets the method in which the frame is executing.
255 /// The method the frame is executing in.
257 public virtual MethodBase GetMethod()
263 /// Gets the offset from the start of the native
264 /// (JIT-compiled) code for the method being executed.
267 /// The offset from the start of the native (JIT-compiled)
268 /// code or the method being executed.
270 public virtual int GetNativeOffset()
276 /// Builds a readable representation of the stack frame.
279 /// A readable representation of the stack frame.
281 public override string ToString ()
283 StringBuilder sb = new StringBuilder ();
285 if (methodBase == null) {
286 sb.Append (Locale.GetText ("<unknown method>"));
288 sb.Append (methodBase.Name);
291 sb.Append (Locale.GetText (" at "));
293 if (ilOffset == OFFSET_UNKNOWN) {
294 sb.Append (Locale.GetText ("<unknown offset>"));
296 sb.Append (Locale.GetText ("offset "));
297 sb.Append (ilOffset);
300 sb.Append (Locale.GetText (" in file:line:column "));
302 if (fileName == null) {
303 sb.Append (Locale.GetText ("<filename unknown>"));
306 // need security check
307 sb.Append (GetFileName ());
309 catch (SecurityException) {
310 sb.Append (Locale.GetText ("<filename unknown>"));
314 sb.AppendFormat (":{0}:{1}", lineNumber, columnNumber);
315 return sb.ToString ();
319 /// Checks whether two objects are equal.
320 /// The objects are assumed equal if and only if either
321 /// both of the references are <code>null</code> or they
322 /// equal via <code>Equals</code> method.
324 /// <param name="obj1">
327 /// <param name="obj2">
331 /// <code>true</code> if the two objects are equal,
332 /// </code>false</code> otherwise.
334 private static bool ObjectsEqual(Object obj1, Object obj2) {
336 return (obj2 == null);
338 return obj1.Equals(obj2);