2 // System.Diagnostics.StackFrame.cs
5 // Alexander Klyubin (klyubin@aqris.com)
6 // Dietmar Maurer (dietmar@ximian.com)
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
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.
35 using System.Reflection;
36 using System.Runtime.CompilerServices;
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) : this() {
106 get_frame_info (2, needFileInfo, out methodBase, out ilOffset,
107 out nativeOffset, out fileName, out lineNumber,
112 /// Initializes a new StackFrame object corresponding to the
113 /// active stack frame.
115 /// <param name="skipFrames">
116 /// The number of frames up the stack to skip.
118 public StackFrame(int skipFrames) {
119 get_frame_info (skipFrames + 2, false, out methodBase, out ilOffset,
120 out nativeOffset, out fileName, out lineNumber,
125 /// Initializes a new StackFrame object corresponding to the
126 /// active stack frame.
128 /// <param name="skipFrames">
129 /// The number of frames up the stack to skip.
131 /// <param name="needFileInfo">
134 public StackFrame(int skipFrames, bool needFileInfo) {
135 get_frame_info (skipFrames + 2, needFileInfo, out methodBase, out ilOffset,
136 out nativeOffset, out fileName, out lineNumber,
141 /// Constructs a fake stack frame that just contains the
142 /// given file name and line number. Use this constructor
143 /// when you do not want to use the debugger's line mapping
146 /// <param name="fileName">
147 /// The given file name.
149 /// <param name="lineNumber">
150 /// The line number in the specified file.
152 // LAMESPEC: According to the MSDN docs, this creates a
153 // fake stack frame. But MS fills out the frame info as well
154 public StackFrame(string fileName, int lineNumber) {
155 get_frame_info (2, false, out methodBase, out ilOffset,
156 out nativeOffset, out fileName, out lineNumber,
158 this.fileName = fileName;
159 this.lineNumber = lineNumber;
160 this.columnNumber = 0;
164 /// Constructs a fake stack frame that just contains the
165 /// given file name and line number. Use this constructor
166 /// when you do not want to use the debugger's line mapping
169 /// <param name="fileName">
170 /// The given file name.
172 /// <param name="lineNumber">
173 /// The line number in the specified file.
175 /// <param name="colNumber">
176 /// The column number in the specified file.
178 // LAMESPEC: According to the MSDN docs, this creates a
179 // fake stack frame. But MS fills out the frame info as well
180 public StackFrame(string fileName,
183 get_frame_info (2, false, out methodBase, out ilOffset,
184 out nativeOffset, out fileName, out lineNumber,
186 this.fileName = fileName;
187 this.lineNumber = lineNumber;
188 this.columnNumber = colNumber;
193 /// Gets the line number in the file containing the code
194 /// being executed. This information is typically extracted
195 /// from the debugging symbols for the executable.
198 /// The file line number or zero if it cannot be determined.
200 public virtual int GetFileLineNumber()
206 /// Gets the column number in the file containing the code
207 /// being executed. This information is typically extracted
208 /// from the debugging symbols for the executable.
211 /// The file column number or zero if it cannot be determined.
213 public virtual int GetFileColumnNumber()
219 /// Gets the file name containing the code being executed.
220 /// This information is typically extracted from the
221 /// debugging symbols for the executable.
224 /// The file name or null if it cannot be determined.
226 public virtual string GetFileName()
232 /// Gets the offset from the start of the IL code for the
233 /// method being executed. This offset may be approximate
234 /// depending on whether the JIT compiler is generating
235 /// debugging code or not.
238 /// The offset from the start of the IL code for the method
241 public virtual int GetILOffset()
247 /// Gets the method in which the frame is executing.
250 /// The method the frame is executing in.
252 public virtual MethodBase GetMethod()
258 /// Gets the offset from the start of the native
259 /// (JIT-compiled) code for the method being executed.
262 /// The offset from the start of the native (JIT-compiled)
263 /// code or the method being executed.
265 public virtual int GetNativeOffset()
271 /// Builds a readable representation of the stack frame.
274 /// A readable representation of the stack frame.
276 public override string ToString() {
277 string methodNameString =
278 (GetMethod() == null)
281 string offsetString =
282 (GetILOffset() == OFFSET_UNKNOWN)
284 : "offset " + GetILOffset();
285 string fileNameString =
286 (GetFileName() == null)
287 ? "<filename unknown>" : GetFileName();
288 return methodNameString + " at " + offsetString
289 + " in file:line:column " + fileNameString
290 + ":" + GetFileLineNumber()
291 + ":" + GetFileColumnNumber();
295 // These are not on the Framework
298 public override bool Equals(Object obj) {
299 if ((obj == null) || (!(obj is StackFrame))) {
303 StackFrame rhs = (StackFrame) obj;
305 if (!ObjectsEqual(GetMethod(), rhs.GetMethod())) {
309 if (!ObjectsEqual(GetFileName(), rhs.GetFileName())) {
313 if (GetFileLineNumber() != rhs.GetFileLineNumber()) {
317 if (GetFileColumnNumber() != rhs.GetFileColumnNumber()) {
321 if (GetILOffset() != rhs.GetILOffset()) {
325 if (GetNativeOffset() != rhs.GetNativeOffset()) {
333 public override int GetHashCode() {
334 return GetFileLineNumber();
339 /// Checks whether two objects are equal.
340 /// The objects are assumed equal if and only if either
341 /// both of the references are <code>null</code> or they
342 /// equal via <code>Equals</code> method.
344 /// <param name="obj1">
347 /// <param name="obj2">
351 /// <code>true</code> if the two objects are equal,
352 /// </code>false</code> otherwise.
354 private static bool ObjectsEqual(Object obj1, Object obj2) {
356 return (obj2 == null);
358 return obj1.Equals(obj2);