1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
6 using System
.Reflection
;
8 namespace System
.Diagnostics
11 /// There is no good reason for the methods of this class to be virtual.
13 public partial class StackFrame
16 /// Reflection information for the method if available, null otherwise.
18 private MethodBase
? _method
;
21 /// Native offset of the current instruction within the current method if available,
22 /// OFFSET_UNKNOWN otherwise.
24 private int _nativeOffset
;
27 /// IL offset of the current instruction within the current method if available,
28 /// OFFSET_UNKNOWN otherwise.
30 private int _ilOffset
;
33 /// Source file name representing the current code location if available, null otherwise.
35 private string? _fileName
;
38 /// Line number representing the current code location if available, 0 otherwise.
40 private int _lineNumber
;
43 /// Column number representing the current code location if available, 0 otherwise.
45 private int _columnNumber
;
48 /// This flag is set to true when the frame represents a rethrow marker.
50 private bool _isLastFrameFromForeignExceptionStackTrace
;
52 private void InitMembers()
54 _nativeOffset
= OFFSET_UNKNOWN
;
55 _ilOffset
= OFFSET_UNKNOWN
;
59 /// Constructs a StackFrame corresponding to the active stack frame.
64 BuildStackFrame(StackTrace
.METHODS_TO_SKIP
, false);
68 /// Constructs a StackFrame corresponding to the active stack frame.
70 public StackFrame(bool needFileInfo
)
73 BuildStackFrame(StackTrace
.METHODS_TO_SKIP
, needFileInfo
);
77 /// Constructs a StackFrame corresponding to a calling stack frame.
79 public StackFrame(int skipFrames
)
82 BuildStackFrame(skipFrames
+ StackTrace
.METHODS_TO_SKIP
, false);
86 /// Constructs a StackFrame corresponding to a calling stack frame.
88 public StackFrame(int skipFrames
, bool needFileInfo
)
91 BuildStackFrame(skipFrames
+ StackTrace
.METHODS_TO_SKIP
, needFileInfo
);
95 /// Constructs a "fake" stack frame, just containing the given file
96 /// name and line number. Use when you don't want to use the
97 /// debugger's line mapping logic.
99 public StackFrame(string? fileName
, int lineNumber
)
103 BuildStackFrame(StackTrace
.METHODS_TO_SKIP
, false);
104 _fileName
= fileName
;
105 _lineNumber
= lineNumber
;
109 /// Constructs a "fake" stack frame, just containing the given file
110 /// name, line number and column number. Use when you don't want to
111 /// use the debugger's line mapping logic.
113 public StackFrame(string? fileName
, int lineNumber
, int colNumber
)
114 : this(fileName
, lineNumber
)
116 _columnNumber
= colNumber
;
120 /// Constant returned when the native or IL offset is unknown
122 public const int OFFSET_UNKNOWN
= -1;
124 internal bool IsLastFrameFromForeignExceptionStackTrace
=> _isLastFrameFromForeignExceptionStackTrace
;
127 /// Returns the method the frame is executing
129 public virtual MethodBase
? GetMethod()
135 /// Returns the offset from the start of the native (jitted) code for the
136 /// method being executed
138 public virtual int GetNativeOffset()
140 return _nativeOffset
;
145 /// Returns the offset from the start of the IL code for the
146 /// method being executed. This offset may be approximate depending
147 /// on whether the jitter is generating debuggable code or not.
149 public virtual int GetILOffset()
155 /// Returns the file name containing the code being executed. This
156 /// information is normally extracted from the debugging symbols
157 /// for the executable.
159 public virtual string? GetFileName()
165 /// Returns the line number in the file containing the code being executed.
166 /// This information is normally extracted from the debugging symbols
167 /// for the executable.
169 public virtual int GetFileLineNumber()
175 /// Returns the column number in the line containing the code being executed.
176 /// This information is normally extracted from the debugging symbols
177 /// for the executable.
179 public virtual int GetFileColumnNumber()
181 return _columnNumber
;
185 /// Builds a readable representation of the stack frame
187 public override string ToString()
189 StringBuilder sb
= new StringBuilder(255);
190 bool includeFileInfoIfAvailable
;
194 sb
.Append(_method
.Name
);
196 // deal with the generic portion of the method
197 if (_method
is MethodInfo methodInfo
&& methodInfo
.IsGenericMethod
)
199 Type
[] typars
= methodInfo
.GetGenericArguments();
203 bool fFirstTyParam
= true;
204 while (k
< typars
.Length
)
206 if (fFirstTyParam
== false)
209 fFirstTyParam
= false;
211 sb
.Append(typars
[k
].Name
);
217 includeFileInfoIfAvailable
= true;
221 includeFileInfoIfAvailable
= AppendStackFrameWithoutMethodBase(sb
);
224 if (includeFileInfoIfAvailable
)
226 sb
.Append(" at offset ");
227 if (_nativeOffset
== OFFSET_UNKNOWN
)
228 sb
.Append("<offset unknown>");
230 sb
.Append(_nativeOffset
);
232 sb
.Append(" in file:line:column ");
233 sb
.Append(_fileName
?? "<filename unknown>");
235 sb
.Append(_lineNumber
);
237 sb
.Append(_columnNumber
);
243 sb
.Append(Environment
.NewLine
);
245 return sb
.ToString();