Fix StyleCop warning SA1008 (opening paren spacing)
[mono-project.git] / netcore / System.Private.CoreLib / shared / System / Diagnostics / StackFrame.cs
bloba5ad117133d53d9a8207713cd281b1d161af0a8a
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.
5 using System.Text;
6 using System.Reflection;
8 namespace System.Diagnostics
10 /// <summary>
11 /// There is no good reason for the methods of this class to be virtual.
12 /// </summary>
13 public partial class StackFrame
15 /// <summary>
16 /// Reflection information for the method if available, null otherwise.
17 /// </summary>
18 private MethodBase? _method;
20 /// <summary>
21 /// Native offset of the current instruction within the current method if available,
22 /// OFFSET_UNKNOWN otherwise.
23 /// </summary>
24 private int _nativeOffset;
26 /// <summary>
27 /// IL offset of the current instruction within the current method if available,
28 /// OFFSET_UNKNOWN otherwise.
29 /// </summary>
30 private int _ilOffset;
32 /// <summary>
33 /// Source file name representing the current code location if available, null otherwise.
34 /// </summary>
35 private string? _fileName;
37 /// <summary>
38 /// Line number representing the current code location if available, 0 otherwise.
39 /// </summary>
40 private int _lineNumber;
42 /// <summary>
43 /// Column number representing the current code location if available, 0 otherwise.
44 /// </summary>
45 private int _columnNumber;
47 /// <summary>
48 /// This flag is set to true when the frame represents a rethrow marker.
49 /// </summary>
50 private bool _isLastFrameFromForeignExceptionStackTrace;
52 private void InitMembers()
54 _nativeOffset = OFFSET_UNKNOWN;
55 _ilOffset = OFFSET_UNKNOWN;
58 /// <summary>
59 /// Constructs a StackFrame corresponding to the active stack frame.
60 /// </summary>
61 public StackFrame()
63 InitMembers();
64 BuildStackFrame(StackTrace.METHODS_TO_SKIP, false);
67 /// <summary>
68 /// Constructs a StackFrame corresponding to the active stack frame.
69 /// </summary>
70 public StackFrame(bool needFileInfo)
72 InitMembers();
73 BuildStackFrame(StackTrace.METHODS_TO_SKIP, needFileInfo);
76 /// <summary>
77 /// Constructs a StackFrame corresponding to a calling stack frame.
78 /// </summary>
79 public StackFrame(int skipFrames)
81 InitMembers();
82 BuildStackFrame(skipFrames + StackTrace.METHODS_TO_SKIP, false);
85 /// <summary>
86 /// Constructs a StackFrame corresponding to a calling stack frame.
87 /// </summary>
88 public StackFrame(int skipFrames, bool needFileInfo)
90 InitMembers();
91 BuildStackFrame(skipFrames + StackTrace.METHODS_TO_SKIP, needFileInfo);
94 /// <summary>
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.
98 /// </summary>
99 public StackFrame(string? fileName, int lineNumber)
101 InitMembers();
103 BuildStackFrame(StackTrace.METHODS_TO_SKIP, false);
104 _fileName = fileName;
105 _lineNumber = lineNumber;
108 /// <summary>
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.
112 /// </summary>
113 public StackFrame(string? fileName, int lineNumber, int colNumber)
114 : this(fileName, lineNumber)
116 _columnNumber = colNumber;
119 /// <summary>
120 /// Constant returned when the native or IL offset is unknown
121 /// </summary>
122 public const int OFFSET_UNKNOWN = -1;
124 internal bool IsLastFrameFromForeignExceptionStackTrace => _isLastFrameFromForeignExceptionStackTrace;
126 /// <summary>
127 /// Returns the method the frame is executing
128 /// </summary>
129 public virtual MethodBase? GetMethod()
131 return _method;
134 /// <summary>
135 /// Returns the offset from the start of the native (jitted) code for the
136 /// method being executed
137 /// </summary>
138 public virtual int GetNativeOffset()
140 return _nativeOffset;
144 /// <summary>
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.
148 /// </summary>
149 public virtual int GetILOffset()
151 return _ilOffset;
154 /// <summary>
155 /// Returns the file name containing the code being executed. This
156 /// information is normally extracted from the debugging symbols
157 /// for the executable.
158 /// </summary>
159 public virtual string? GetFileName()
161 return _fileName;
164 /// <summary>
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.
168 /// </summary>
169 public virtual int GetFileLineNumber()
171 return _lineNumber;
174 /// <summary>
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.
178 /// </summary>
179 public virtual int GetFileColumnNumber()
181 return _columnNumber;
184 /// <summary>
185 /// Builds a readable representation of the stack frame
186 /// </summary>
187 public override string ToString()
189 StringBuilder sb = new StringBuilder(255);
190 bool includeFileInfoIfAvailable;
192 if (_method != null)
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();
201 sb.Append('<');
202 int k = 0;
203 bool fFirstTyParam = true;
204 while (k < typars.Length)
206 if (fFirstTyParam == false)
207 sb.Append(',');
208 else
209 fFirstTyParam = false;
211 sb.Append(typars[k].Name);
212 k++;
215 sb.Append('>');
217 includeFileInfoIfAvailable = true;
219 else
221 includeFileInfoIfAvailable = AppendStackFrameWithoutMethodBase(sb);
224 if (includeFileInfoIfAvailable)
226 sb.Append(" at offset ");
227 if (_nativeOffset == OFFSET_UNKNOWN)
228 sb.Append("<offset unknown>");
229 else
230 sb.Append(_nativeOffset);
232 sb.Append(" in file:line:column ");
233 sb.Append(_fileName ?? "<filename unknown>");
234 sb.Append(':');
235 sb.Append(_lineNumber);
236 sb.Append(':');
237 sb.Append(_columnNumber);
239 else
241 sb.Append("<null>");
243 sb.Append(Environment.NewLine);
245 return sb.ToString();