| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- // See the LICENSE file in the project root for more information.
- using System.Text;
- using System;
- using System.IO;
- using System.Reflection;
- namespace System.Diagnostics
- {
- /// <summary>
- /// There is no good reason for the methods of this class to be virtual.
- /// </summary>
- public partial class StackFrame
- {
- /// <summary>
- /// Reflection information for the method if available, null otherwise.
- /// </summary>
- private MethodBase _method;
- /// <summary>
- /// Native offset of the current instruction within the current method if available,
- /// OFFSET_UNKNOWN otherwise.
- /// </summary>
- private int _nativeOffset;
- /// <summary>
- /// IL offset of the current instruction within the current method if available,
- /// OFFSET_UNKNOWN otherwise.
- /// </summary>
- private int _ilOffset;
- /// <summary>
- /// Source file name representing the current code location if available, null otherwise.
- /// </summary>
- private string _fileName;
- /// <summary>
- /// Line number representing the current code location if available, 0 otherwise.
- /// </summary>
- private int _lineNumber;
- /// <summary>
- /// Column number representing the current code location if available, 0 otherwise.
- /// </summary>
- private int _columnNumber;
- /// <summary>
- /// This flag is set to true when the frame represents a rethrow marker.
- /// </summary>
- private bool _isLastFrameFromForeignExceptionStackTrace;
- private void InitMembers()
- {
- _method = null;
- _nativeOffset = OFFSET_UNKNOWN;
- _ilOffset = OFFSET_UNKNOWN;
- _fileName = null;
- _lineNumber = 0;
- _columnNumber = 0;
- _isLastFrameFromForeignExceptionStackTrace = false;
- }
- /// <summary>
- /// Constructs a StackFrame corresponding to the active stack frame.
- /// </summary>
- public StackFrame()
- {
- InitMembers();
- BuildStackFrame(0 + StackTrace.METHODS_TO_SKIP, false);
- }
- /// <summary>
- /// Constructs a StackFrame corresponding to the active stack frame.
- /// </summary>
- public StackFrame(bool needFileInfo)
- {
- InitMembers();
- BuildStackFrame(0 + StackTrace.METHODS_TO_SKIP, needFileInfo);
- }
- /// <summary>
- /// Constructs a StackFrame corresponding to a calling stack frame.
- /// </summary>
- public StackFrame(int skipFrames)
- {
- InitMembers();
- BuildStackFrame(skipFrames + StackTrace.METHODS_TO_SKIP, false);
- }
- /// <summary>
- /// Constructs a StackFrame corresponding to a calling stack frame.
- /// </summary>
- public StackFrame(int skipFrames, bool needFileInfo)
- {
- InitMembers();
- BuildStackFrame(skipFrames + StackTrace.METHODS_TO_SKIP, needFileInfo);
- }
- /// <summary>
- /// Constructs a "fake" stack frame, just containing the given file
- /// name and line number. Use when you don't want to use the
- /// debugger's line mapping logic.
- /// </summary>
- public StackFrame(string fileName, int lineNumber)
- {
- InitMembers();
- BuildStackFrame(StackTrace.METHODS_TO_SKIP, false);
- _fileName = fileName;
- _lineNumber = lineNumber;
- _columnNumber = 0;
- }
- /// <summary>
- /// Constructs a "fake" stack frame, just containing the given file
- /// name, line number and column number. Use when you don't want to
- /// use the debugger's line mapping logic.
- /// </summary>
- public StackFrame(string fileName, int lineNumber, int colNumber)
- {
- InitMembers();
- BuildStackFrame(StackTrace.METHODS_TO_SKIP, false);
- _fileName = fileName;
- _lineNumber = lineNumber;
- _columnNumber = colNumber;
- }
- /// <summary>
- /// Constant returned when the native or IL offset is unknown
- /// </summary>
- public const int OFFSET_UNKNOWN = -1;
- internal virtual void SetMethodBase(MethodBase mb)
- {
- _method = mb;
- }
- internal virtual void SetOffset(int iOffset)
- {
- _nativeOffset = iOffset;
- }
- internal virtual void SetILOffset(int iOffset)
- {
- _ilOffset = iOffset;
- }
- internal virtual void SetFileName(string strFName)
- {
- _fileName = strFName;
- }
- internal virtual void SetLineNumber(int iLine)
- {
- _lineNumber = iLine;
- }
- internal virtual void SetColumnNumber(int iCol)
- {
- _columnNumber = iCol;
- }
- internal virtual void SetIsLastFrameFromForeignExceptionStackTrace(bool fIsLastFrame)
- {
- _isLastFrameFromForeignExceptionStackTrace = fIsLastFrame;
- }
- internal virtual bool GetIsLastFrameFromForeignExceptionStackTrace()
- {
- return _isLastFrameFromForeignExceptionStackTrace;
- }
- /// <summary>
- /// Returns the method the frame is executing
- /// </summary>
- public virtual MethodBase GetMethod()
- {
- return _method;
- }
- /// <summary>
- /// Returns the offset from the start of the native (jitted) code for the
- /// method being executed
- /// </summary>
- public virtual int GetNativeOffset()
- {
- return _nativeOffset;
- }
- /// <summary>
- /// Returns the offset from the start of the IL code for the
- /// method being executed. This offset may be approximate depending
- /// on whether the jitter is generating debuggable code or not.
- /// </summary>
- public virtual int GetILOffset()
- {
- return _ilOffset;
- }
- /// <summary>
- /// Returns the file name containing the code being executed. This
- /// information is normally extracted from the debugging symbols
- /// for the executable.
- /// </summary>
- public virtual string GetFileName()
- {
- return _fileName;
- }
- /// <summary>
- /// Returns the line number in the file containing the code being executed.
- /// This information is normally extracted from the debugging symbols
- /// for the executable.
- /// </summary>
- public virtual int GetFileLineNumber()
- {
- return _lineNumber;
- }
- /// <summary>
- /// Returns the column number in the line containing the code being executed.
- /// This information is normally extracted from the debugging symbols
- /// for the executable.
- /// </summary>
- public virtual int GetFileColumnNumber()
- {
- return _columnNumber;
- }
- /// <summary>
- /// Builds a readable representation of the stack frame
- /// </summary>
- public override string ToString()
- {
- StringBuilder sb = new StringBuilder(255);
- bool includeFileInfoIfAvailable;
- if (_method != null)
- {
- sb.Append(_method.Name);
- // deal with the generic portion of the method
- if (_method is MethodInfo methodInfo && methodInfo.IsGenericMethod)
- {
- Type[] typars = methodInfo.GetGenericArguments();
- sb.Append('<');
- int k = 0;
- bool fFirstTyParam = true;
- while (k < typars.Length)
- {
- if (fFirstTyParam == false)
- sb.Append(',');
- else
- fFirstTyParam = false;
- sb.Append(typars[k].Name);
- k++;
- }
- sb.Append('>');
- }
- includeFileInfoIfAvailable = true;
- }
- else
- {
- includeFileInfoIfAvailable = AppendStackFrameWithoutMethodBase(sb);
- }
- if (includeFileInfoIfAvailable)
- {
- sb.Append(" at offset ");
- if (_nativeOffset == OFFSET_UNKNOWN)
- sb.Append("<offset unknown>");
- else
- sb.Append(_nativeOffset);
- sb.Append(" in file:line:column ");
- bool useFileName = (_fileName != null);
- if (!useFileName)
- sb.Append("<filename unknown>");
- else
- sb.Append(_fileName);
- sb.Append(':');
- sb.Append(_lineNumber);
- sb.Append(':');
- sb.Append(_columnNumber);
- }
- else
- {
- sb.Append("<null>");
- }
- sb.Append(Environment.NewLine);
- return sb.ToString();
- }
- }
- }
|