diff options
Diffstat (limited to 'src/mscorlib/src/System/Diagnostics/Stackframe.cs')
-rw-r--r-- | src/mscorlib/src/System/Diagnostics/Stackframe.cs | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/Diagnostics/Stackframe.cs b/src/mscorlib/src/System/Diagnostics/Stackframe.cs new file mode 100644 index 0000000000..397c3e12e6 --- /dev/null +++ b/src/mscorlib/src/System/Diagnostics/Stackframe.cs @@ -0,0 +1,348 @@ +// 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. + +namespace System.Diagnostics { + + using System.Text; + using System; + using System.IO; + using System.Reflection; + using System.Security.Permissions; + using System.Diagnostics.Contracts; + + // There is no good reason for the methods of this class to be virtual. + // In order to ensure trusted code can trust the data it gets from a + // StackTrace, we use an InheritanceDemand to prevent partially-trusted + // subclasses. +#if !FEATURE_CORECLR + [SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode=true)] +#endif + [Serializable] + [System.Runtime.InteropServices.ComVisible(true)] + public class StackFrame + { + private MethodBase method; + private int offset; + private int ILOffset; + private String strFileName; + private int iLineNumber; + private int iColumnNumber; + +#if FEATURE_EXCEPTIONDISPATCHINFO + [System.Runtime.Serialization.OptionalField] + private bool fIsLastFrameFromForeignExceptionStackTrace; +#endif // FEATURE_EXCEPTIONDISPATCHINFO + + internal void InitMembers() + { + method = null; + offset = OFFSET_UNKNOWN; + ILOffset = OFFSET_UNKNOWN; + strFileName = null; + iLineNumber = 0; + iColumnNumber = 0; +#if FEATURE_EXCEPTIONDISPATCHINFO + fIsLastFrameFromForeignExceptionStackTrace = false; +#endif // FEATURE_EXCEPTIONDISPATCHINFO + + } + + // Constructs a StackFrame corresponding to the active stack frame. +#if FEATURE_CORECLR + [System.Security.SecuritySafeCritical] +#endif + public StackFrame() + { + InitMembers(); + BuildStackFrame (0 + StackTrace.METHODS_TO_SKIP, false);// iSkipFrames=0 + } + + // Constructs a StackFrame corresponding to the active stack frame. + #if FEATURE_CORECLR + [System.Security.SecurityCritical] // auto-generated + #endif + public StackFrame(bool fNeedFileInfo) + { + InitMembers(); + BuildStackFrame (0 + StackTrace.METHODS_TO_SKIP, fNeedFileInfo);// iSkipFrames=0 + } + + // Constructs a StackFrame corresponding to a calling stack frame. + // + public StackFrame(int skipFrames) + { + InitMembers(); + BuildStackFrame (skipFrames + StackTrace.METHODS_TO_SKIP, false); + } + + // Constructs a StackFrame corresponding to a calling stack frame. + // + #if FEATURE_CORECLR + [System.Security.SecurityCritical] // auto-generated + #endif + public StackFrame(int skipFrames, bool fNeedFileInfo) + { + InitMembers(); + BuildStackFrame (skipFrames + StackTrace.METHODS_TO_SKIP, fNeedFileInfo); + } + + + // Called from the class "StackTrace" + // + internal StackFrame(bool DummyFlag1, bool DummyFlag2) + { + InitMembers(); + } + + // 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. + // + public StackFrame(String fileName, int lineNumber) + { + InitMembers(); + BuildStackFrame (StackTrace.METHODS_TO_SKIP, false); + strFileName = fileName; + iLineNumber = lineNumber; + iColumnNumber = 0; + } + + + // 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. + // + public StackFrame(String fileName, int lineNumber, int colNumber) + { + InitMembers(); + BuildStackFrame (StackTrace.METHODS_TO_SKIP, false); + strFileName = fileName; + iLineNumber = lineNumber; + iColumnNumber = colNumber; + } + + + // Constant returned when the native or IL offset is unknown + public const int OFFSET_UNKNOWN = -1; + + + internal virtual void SetMethodBase (MethodBase mb) + { + method = mb; + } + + internal virtual void SetOffset (int iOffset) + { + offset = iOffset; + } + + internal virtual void SetILOffset (int iOffset) + { + ILOffset = iOffset; + } + + internal virtual void SetFileName (String strFName) + { + strFileName = strFName; + } + + internal virtual void SetLineNumber (int iLine) + { + iLineNumber = iLine; + } + + internal virtual void SetColumnNumber (int iCol) + { + iColumnNumber = iCol; + } + +#if FEATURE_EXCEPTIONDISPATCHINFO + internal virtual void SetIsLastFrameFromForeignExceptionStackTrace (bool fIsLastFrame) + { + fIsLastFrameFromForeignExceptionStackTrace = fIsLastFrame; + } + + internal virtual bool GetIsLastFrameFromForeignExceptionStackTrace() + { + return fIsLastFrameFromForeignExceptionStackTrace; + } +#endif // FEATURE_EXCEPTIONDISPATCHINFO + + // Returns the method the frame is executing + // + public virtual MethodBase GetMethod () + { + Contract.Ensures(Contract.Result<MethodBase>() != null); + + return method; + } + + // Returns the offset from the start of the native (jitted) code for the + // method being executed + // + public virtual int GetNativeOffset () + { + return offset; + } + + + // 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. + // + public virtual int GetILOffset() + { + return ILOffset; + } + + // Returns the file name containing the code being executed. This + // information is normally extracted from the debugging symbols + // for the executable. + // + #if FEATURE_CORECLR + [System.Security.SecurityCritical] // auto-generated + #else + [System.Security.SecuritySafeCritical] + #endif + public virtual String GetFileName() + { + if (strFileName != null) + { + // This isn't really correct, but we don't have + // a permission that protects discovery of potentially + // local urls so we'll use this. + + FileIOPermission perm = new FileIOPermission( PermissionState.None ); + perm.AllFiles = FileIOPermissionAccess.PathDiscovery; + perm.Demand(); + } + + return strFileName; + } + + // Returns the line number in the file containing the code being executed. + // This information is normally extracted from the debugging symbols + // for the executable. + // + public virtual int GetFileLineNumber() + { + return iLineNumber; + } + + // Returns the column number in the line containing the code being executed. + // This information is normally extracted from the debugging symbols + // for the executable. + // + public virtual int GetFileColumnNumber() + { + return iColumnNumber; + } + + + // Builds a readable representation of the stack frame + // + [System.Security.SecuritySafeCritical] // auto-generated + public override String ToString() + { + StringBuilder sb = new StringBuilder(255); + + if (method != null) + { + sb.Append(method.Name); + + // deal with the generic portion of the method + if (method is MethodInfo && ((MethodInfo)method).IsGenericMethod) + { + Type[] typars = ((MethodInfo)method).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('>'); + } + + sb.Append(" at offset "); + if (offset == OFFSET_UNKNOWN) + sb.Append("<offset unknown>"); + else + sb.Append(offset); + + sb.Append(" in file:line:column "); + + bool useFileName = (strFileName != null); + + if (useFileName) + { + try + { + // This isn't really correct, but we don't have + // a permission that protects discovery of potentially + // local urls so we'll use this. + + FileIOPermission perm = new FileIOPermission(PermissionState.None); + perm.AllFiles = FileIOPermissionAccess.PathDiscovery; + perm.Demand(); + } + catch (System.Security.SecurityException) + { + useFileName = false; + } + } + + if (!useFileName) + sb.Append("<filename unknown>"); + else + sb.Append(strFileName); + sb.Append(':'); + sb.Append(iLineNumber); + sb.Append(':'); + sb.Append(iColumnNumber); + } + else + { + sb.Append("<null>"); + } + sb.Append(Environment.NewLine); + + return sb.ToString(); + } + + + private void BuildStackFrame(int skipFrames, bool fNeedFileInfo) + { + using (StackFrameHelper StackF = new StackFrameHelper(null)) + { + StackF.InitializeSourceInfo(0, fNeedFileInfo, null); + + int iNumOfFrames = StackF.GetNumberOfFrames(); + + skipFrames += StackTrace.CalculateFramesToSkip(StackF, iNumOfFrames); + + if ((iNumOfFrames - skipFrames) > 0) + { + method = StackF.GetMethodBase(skipFrames); + offset = StackF.GetOffset(skipFrames); + ILOffset = StackF.GetILOffset(skipFrames); + if (fNeedFileInfo) + { + strFileName = StackF.GetFilename(skipFrames); + iLineNumber = StackF.GetLineNumber(skipFrames); + iColumnNumber = StackF.GetColumnNumber(skipFrames); + } + } + } + } + } +} |