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