File: system\diagnostics\stackframe.cs
Project: ndp\clr\src\bcl\mscorlib.csproj (mscorlib)
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
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);
                    }
                }
            }
        }
    }
}