2 // System.Diagnostics.StackFrame.cs
\r
5 // Alexander Klyubin (klyubin@aqris.com)
\r
6 // Dietmar Maurer (dietmar@ximian.com)
\r
12 using System.Reflection;
\r
13 using System.Runtime.CompilerServices;
\r
15 namespace System.Diagnostics {
\r
21 public class StackFrame {
\r
23 /// Constant returned when the native or IL offset is unknown.
\r
25 public const int OFFSET_UNKNOWN = -1;
\r
28 /// Offset from the start of the IL code for the method
\r
31 private int ilOffset = OFFSET_UNKNOWN;
\r
34 /// Offset from the start of the native code for the method
\r
37 private int nativeOffset = OFFSET_UNKNOWN;
\r
40 /// Method associated with this stack frame.
\r
42 private MethodBase methodBase;
\r
47 private string fileName;
\r
52 private int lineNumber;
\r
57 private int columnNumber;
\r
59 static bool get_frame_info (int skip, bool needFileInfo, out MethodBase method,
\r
60 out int iloffset, out int native_offset,
\r
61 out string file, out int line, out int column)
\r
72 [MethodImplAttribute(MethodImplOptions.InternalCall)]
\r
73 extern static bool get_frame_info (int skip, bool needFileInfo, out MethodBase method,
\r
74 out int iloffset, out int native_offset,
\r
75 out string file, out int line, out int column);
\r
78 /// Initializes a new StackFrame object corresponding to the
\r
79 /// active stack frame.
\r
81 public StackFrame()
\r
83 get_frame_info (2, false, out methodBase, out ilOffset,
\r
84 out nativeOffset, out fileName, out lineNumber,
\r
89 /// Initializes a new StackFrame object corresponding to the
\r
90 /// active stack frame.
\r
92 /// <param name="needFileInfo">
\r
95 public StackFrame(bool needFileInfo) : this() {
\r
96 get_frame_info (2, needFileInfo, out methodBase, out ilOffset,
\r
97 out nativeOffset, out fileName, out lineNumber,
\r
102 /// Initializes a new StackFrame object corresponding to the
\r
103 /// active stack frame.
\r
105 /// <param name="skipFrames">
\r
106 /// The number of frames up the stack to skip.
\r
108 public StackFrame(int skipFrames) {
\r
109 get_frame_info (skipFrames + 2, false, out methodBase, out ilOffset,
\r
110 out nativeOffset, out fileName, out lineNumber,
\r
111 out columnNumber);
\r
115 /// Initializes a new StackFrame object corresponding to the
\r
116 /// active stack frame.
\r
118 /// <param name="skipFrames">
\r
119 /// The number of frames up the stack to skip.
\r
121 /// <param name="needFileInfo">
\r
124 public StackFrame(int skipFrames, bool needFileInfo) {
\r
125 get_frame_info (skipFrames + 2, needFileInfo, out methodBase, out ilOffset,
\r
126 out nativeOffset, out fileName, out lineNumber,
\r
131 /// Constructs a fake stack frame that just contains the
\r
132 /// given file name and line number. Use this constructor
\r
133 /// when you do not want to use the debugger's line mapping
\r
136 /// <param name="fileName">
\r
137 /// The given file name.
\r
139 /// <param name="lineNumber">
\r
140 /// The line number in the specified file.
\r
142 // LAMESPEC: According to the MSDN docs, this creates a
\r
143 // fake stack frame. But MS fills out the frame info as well
\r
144 public StackFrame(string fileName, int lineNumber) {
\r
145 get_frame_info (2, false, out methodBase, out ilOffset,
\r
146 out nativeOffset, out fileName, out lineNumber,
\r
148 this.fileName = fileName;
\r
149 this.lineNumber = lineNumber;
\r
150 this.columnNumber = 0;
\r
154 /// Constructs a fake stack frame that just contains the
\r
155 /// given file name and line number. Use this constructor
\r
156 /// when you do not want to use the debugger's line mapping
\r
159 /// <param name="fileName">
\r
160 /// The given file name.
\r
162 /// <param name="lineNumber">
\r
163 /// The line number in the specified file.
\r
165 /// <param name="colNumber">
\r
166 /// The column number in the specified file.
\r
168 // LAMESPEC: According to the MSDN docs, this creates a
\r
169 // fake stack frame. But MS fills out the frame info as well
\r
170 public StackFrame(string fileName,
\r
173 get_frame_info (2, false, out methodBase, out ilOffset,
\r
174 out nativeOffset, out fileName, out lineNumber,
\r
176 this.fileName = fileName;
\r
177 this.lineNumber = lineNumber;
\r
178 this.columnNumber = colNumber;
\r
183 /// Gets the line number in the file containing the code
\r
184 /// being executed. This information is typically extracted
\r
185 /// from the debugging symbols for the executable.
\r
188 /// The file line number or zero if it cannot be determined.
\r
190 public virtual int GetFileLineNumber()
\r
196 /// Gets the column number in the file containing the code
\r
197 /// being executed. This information is typically extracted
\r
198 /// from the debugging symbols for the executable.
\r
201 /// The file column number or zero if it cannot be determined.
\r
203 public virtual int GetFileColumnNumber()
\r
205 return columnNumber;
\r
209 /// Gets the file name containing the code being executed.
\r
210 /// This information is typically extracted from the
\r
211 /// debugging symbols for the executable.
\r
214 /// The file name or null if it cannot be determined.
\r
216 public virtual string GetFileName()
\r
222 /// Gets the offset from the start of the IL code for the
\r
223 /// method being executed. This offset may be approximate
\r
224 /// depending on whether the JIT compiler is generating
\r
225 /// debugging code or not.
\r
228 /// The offset from the start of the IL code for the method
\r
229 /// being executed.
\r
231 public virtual int GetILOffset()
\r
237 /// Gets the method in which the frame is executing.
\r
240 /// The method the frame is executing in.
\r
242 public virtual MethodBase GetMethod()
\r
248 /// Gets the offset from the start of the native
\r
249 /// (JIT-compiled) code for the method being executed.
\r
252 /// The offset from the start of the native (JIT-compiled)
\r
253 /// code or the method being executed.
\r
255 public virtual int GetNativeOffset()
\r
257 return nativeOffset;
\r
261 /// Builds a readable representation of the stack frame.
\r
264 /// A readable representation of the stack frame.
\r
266 public override string ToString() {
\r
267 string methodNameString =
\r
268 (GetMethod() == null)
\r
269 ? "<unknown method>"
\r
270 : GetMethod().Name;
\r
271 string offsetString =
\r
272 (GetILOffset() == OFFSET_UNKNOWN)
\r
273 ? "<unknown offset>"
\r
274 : "offset " + GetILOffset();
\r
275 string fileNameString =
\r
276 (GetFileName() == null)
\r
277 ? "<filename unknown>" : GetFileName();
\r
278 return methodNameString + " at " + offsetString
\r
279 + " in file:line:column " + fileNameString
\r
280 + ":" + GetFileLineNumber()
\r
281 + ":" + GetFileColumnNumber();
\r
284 public override bool Equals(Object obj) {
\r
285 if ((obj == null) || (!(obj is StackFrame))) {
\r
289 StackFrame rhs = (StackFrame) obj;
\r
291 if (!ObjectsEqual(GetMethod(), rhs.GetMethod())) {
\r
295 if (!ObjectsEqual(GetFileName(), rhs.GetFileName())) {
\r
299 if (GetFileLineNumber() != rhs.GetFileLineNumber()) {
\r
303 if (GetFileColumnNumber() != rhs.GetFileColumnNumber()) {
\r
307 if (GetILOffset() != rhs.GetILOffset()) {
\r
311 if (GetNativeOffset() != rhs.GetNativeOffset()) {
\r
319 public override int GetHashCode() {
\r
320 return GetFileLineNumber();
\r
324 /// Checks whether two objects are equal.
\r
325 /// The objects are assumed equal if and only if either
\r
326 /// both of the references are <code>null</code> or they
\r
327 /// equal via <code>Equals</code> method.
\r
329 /// <param name="obj1">
\r
332 /// <param name="obj2">
\r
336 /// <code>true</code> if the two objects are equal,
\r
337 /// </code>false</code> otherwise.
\r
339 private static bool ObjectsEqual(Object obj1, Object obj2) {
\r
340 if (obj1 == null) {
\r
341 return (obj2 == null);
\r
343 return obj1.Equals(obj2);
\r