The Labs \ Source Viewer \ SSCLI \ System.Diagnostics \ TraceFormat

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. namespace System.Diagnostics
  16. {
  17.     using System.Text;
  18.     using System.Threading;
  19.     using System;
  20.     using System.Security;
  21.     using System.Security.Permissions;
  22.     using System.IO;
  23.     using System.Reflection;
  24.     using System.Runtime.InteropServices;
  25.     using System.Runtime.CompilerServices;
  26.     using System.Globalization;
  27.     using System.Runtime.Serialization;
  28.    
  29.     // READ ME:
  30.     // Modifying the order or fields of this object may require other changes
  31.     // to the unmanaged definition of the StackFrameHelper class, in
  32.     // VM\DebugDebugger.h. The binder will catch some of these layout problems.
  33.     [Serializable()]
  34.     internal class StackFrameHelper
  35.     {
  36.         [NonSerialized()]
  37.         private Thread targetThread;
  38.         private int[] rgiOffset;
  39.         private int[] rgiILOffset;
  40.         // this field is here only for backwards compatibility of serialization format
  41.         private MethodBase[] rgMethodBase;
  42.        
  43.         #pragma warning disable 414 // Field is not used from managed.
  44.         // dynamicMethods is an array of System.Resolver objects, used to keep
  45.         // DynamicMethodDescs alive for the lifetime of StackFrameHelper.
  46.         private object dynamicMethods;
  47.         #pragma warning restore 414
  48.        
  49.         [NonSerialized()]
  50.         private RuntimeMethodHandle[] rgMethodHandle;
  51.         private string[] rgFilename;
  52.         private int[] rgiLineNumber;
  53.         private int[] rgiColumnNumber;
  54.         private int iFrameCount;
  55.         private bool fNeedFileInfo;
  56.        
  57.        
  58.         public StackFrameHelper(bool fNeedFileLineColInfo, Thread target)
  59.         {
  60.             targetThread = target;
  61.             rgMethodBase = null;
  62.             rgMethodHandle = null;
  63.             rgiOffset = null;
  64.             rgiILOffset = null;
  65.             rgFilename = null;
  66.             rgiLineNumber = null;
  67.             rgiColumnNumber = null;
  68.             dynamicMethods = null;
  69.             iFrameCount = 512;
  70.             //read by the internal to EE method: this is the
  71.             // number of requested frames
  72.             fNeedFileInfo = fNeedFileLineColInfo;
  73.         }
  74.        
  75.         public virtual MethodBase GetMethodBase(int i)
  76.         {
  77.             // There may be a better way to do this.
  78.             // we got RuntimeMethodHandles here and we need to go to MethodBase
  79.             // but we don't know whether the reflection info has been initialized
  80.             // or not. So we call GetMethods and GetConstructors on the type
  81.             // and then we fetch the proper MethodBase!!
  82.             RuntimeMethodHandle mh = rgMethodHandle[i];
  83.            
  84.             if (mh.IsNullHandle())
  85.                 return null;
  86.            
  87.             mh = mh.GetTypicalMethodDefinition();
  88.            
  89.             return RuntimeType.GetMethodBase(mh);
  90.         }
  91.        
  92.         public virtual int GetOffset(int i)
  93.         {
  94.             return rgiOffset[i];
  95.         }
  96.         public virtual int GetILOffset(int i)
  97.         {
  98.             return rgiILOffset[i];
  99.         }
  100.         public virtual string GetFilename(int i)
  101.         {
  102.             return rgFilename[i];
  103.         }
  104.         public virtual int GetLineNumber(int i)
  105.         {
  106.             return rgiLineNumber[i];
  107.         }
  108.         public virtual int GetColumnNumber(int i)
  109.         {
  110.             return rgiColumnNumber[i];
  111.         }
  112.         public virtual int GetNumberOfFrames()
  113.         {
  114.             return iFrameCount;
  115.         }
  116.         public virtual void SetNumberOfFrames(int i)
  117.         {
  118.             iFrameCount = i;
  119.         }
  120.        
  121.         //
  122.         // serialization implementation
  123.         //
  124.         [OnSerializing()]
  125.         void OnSerializing(StreamingContext context)
  126.         {
  127.             rgMethodBase = (rgMethodHandle == null) ? null : new MethodBase[rgMethodHandle.Length];
  128.             if (rgMethodHandle != null) {
  129.                 for (int i = 0; i < rgMethodHandle.Length; i++) {
  130.                     if (!rgMethodHandle[i].IsNullHandle())
  131.                         rgMethodBase[i] = RuntimeType.GetMethodBase(rgMethodHandle[i]);
  132.                 }
  133.             }
  134.         }
  135.        
  136.         [OnSerialized()]
  137.         void OnSerialized(StreamingContext context)
  138.         {
  139.             // after we are done serializing null the rgMethodBase field
  140.             rgMethodBase = null;
  141.         }
  142.        
  143.         [OnDeserialized()]
  144.         void OnDeserialized(StreamingContext context)
  145.         {
  146.             // after we are done deserializing we need to transform the rgMethodBase in rgMethodHandle
  147.             rgMethodHandle = (rgMethodBase == null) ? null : new RuntimeMethodHandle[rgMethodBase.Length];
  148.             if (rgMethodBase != null) {
  149.                 for (int i = 0; i < rgMethodBase.Length; i++) {
  150.                     if (rgMethodBase[i] != null)
  151.                         rgMethodHandle[i] = rgMethodBase[i].MethodHandle;
  152.                 }
  153.             }
  154.             rgMethodBase = null;
  155.         }
  156.     }
  157.    
  158.    
  159.     // Class which represents a description of a stack trace
  160.     // There is no good reason for the methods of this class to be virtual.
  161.     // In order to ensure trusted code can trust the data it gets from a
  162.     // StackTrace, we use an InheritanceDemand to prevent partially-trusted
  163.     // subclasses.
  164.     [SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
  165.     [Serializable()]
  166.     [System.Runtime.InteropServices.ComVisible(true)]
  167.     public class StackTrace
  168.     {
  169.         private StackFrame[] frames;
  170.         private int m_iNumOfFrames;
  171.         public const int METHODS_TO_SKIP = 0;
  172.         private int m_iMethodsToSkip;
  173.        
  174.         // Constructs a stack trace from the current location.
  175.         public StackTrace()
  176.         {
  177.             m_iNumOfFrames = 0;
  178.             m_iMethodsToSkip = 0;
  179.             CaptureStackTrace(METHODS_TO_SKIP, false, null, null);
  180.         }
  181.        
  182.         // Constructs a stack trace from the current location.
  183.         //
  184.         public StackTrace(bool fNeedFileInfo)
  185.         {
  186.             m_iNumOfFrames = 0;
  187.             m_iMethodsToSkip = 0;
  188.             CaptureStackTrace(METHODS_TO_SKIP, fNeedFileInfo, null, null);
  189.         }
  190.        
  191.         // Constructs a stack trace from the current location, in a caller's
  192.         // frame
  193.         //
  194.         public StackTrace(int skipFrames)
  195.         {
  196.            
  197.             if (skipFrames < 0)
  198.                 throw new ArgumentOutOfRangeException("skipFrames", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  199.            
  200.             m_iNumOfFrames = 0;
  201.             m_iMethodsToSkip = 0;
  202.            
  203.             CaptureStackTrace(skipFrames + METHODS_TO_SKIP, false, null, null);
  204.         }
  205.        
  206.         // Constructs a stack trace from the current location, in a caller's
  207.         // frame
  208.         //
  209.         public StackTrace(int skipFrames, bool fNeedFileInfo)
  210.         {
  211.            
  212.             if (skipFrames < 0)
  213.                 throw new ArgumentOutOfRangeException("skipFrames", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  214.            
  215.             m_iNumOfFrames = 0;
  216.             m_iMethodsToSkip = 0;
  217.            
  218.             CaptureStackTrace(skipFrames + METHODS_TO_SKIP, fNeedFileInfo, null, null);
  219.         }
  220.        
  221.        
  222.         // Constructs a stack trace from the current location.
  223.         public StackTrace(Exception e)
  224.         {
  225.             if (e == null)
  226.                 throw new ArgumentNullException("e");
  227.            
  228.             m_iNumOfFrames = 0;
  229.             m_iMethodsToSkip = 0;
  230.             CaptureStackTrace(METHODS_TO_SKIP, false, null, e);
  231.         }
  232.        
  233.         // Constructs a stack trace from the current location.
  234.         //
  235.         public StackTrace(Exception e, bool fNeedFileInfo)
  236.         {
  237.             if (e == null)
  238.                 throw new ArgumentNullException("e");
  239.            
  240.             m_iNumOfFrames = 0;
  241.             m_iMethodsToSkip = 0;
  242.             CaptureStackTrace(METHODS_TO_SKIP, fNeedFileInfo, null, e);
  243.         }
  244.        
  245.         // Constructs a stack trace from the current location, in a caller's
  246.         // frame
  247.         //
  248.         public StackTrace(Exception e, int skipFrames)
  249.         {
  250.             if (e == null)
  251.                 throw new ArgumentNullException("e");
  252.            
  253.             if (skipFrames < 0)
  254.                 throw new ArgumentOutOfRangeException("skipFrames", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  255.            
  256.             m_iNumOfFrames = 0;
  257.             m_iMethodsToSkip = 0;
  258.            
  259.             CaptureStackTrace(skipFrames + METHODS_TO_SKIP, false, null, e);
  260.         }
  261.        
  262.         // Constructs a stack trace from the current location, in a caller's
  263.         // frame
  264.         //
  265.         public StackTrace(Exception e, int skipFrames, bool fNeedFileInfo)
  266.         {
  267.             if (e == null)
  268.                 throw new ArgumentNullException("e");
  269.            
  270.             if (skipFrames < 0)
  271.                 throw new ArgumentOutOfRangeException("skipFrames", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  272.            
  273.             m_iNumOfFrames = 0;
  274.             m_iMethodsToSkip = 0;
  275.            
  276.             CaptureStackTrace(skipFrames + METHODS_TO_SKIP, fNeedFileInfo, null, e);
  277.         }
  278.        
  279.        
  280.         // Constructs a "fake" stack trace, just containing a single frame.
  281.         // Does not have the overhead of a full stack trace.
  282.         //
  283.         public StackTrace(StackFrame frame)
  284.         {
  285.             frames = new StackFrame[1];
  286.             frames[0] = frame;
  287.             m_iMethodsToSkip = 0;
  288.             m_iNumOfFrames = 1;
  289.         }
  290.        
  291.        
  292.         // Constructs a stack trace for the given thread
  293.         //
  294.         public StackTrace(Thread targetThread, bool needFileInfo)
  295.         {
  296.             m_iNumOfFrames = 0;
  297.             m_iMethodsToSkip = 0;
  298.            
  299.             CaptureStackTrace(METHODS_TO_SKIP, needFileInfo, targetThread, null);
  300.            
  301.         }
  302.        
  303.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  304.         static internal extern void GetStackFramesInternal(StackFrameHelper sfh, int iSkip, Exception e);
  305.        
  306.         static internal int CalculateFramesToSkip(StackFrameHelper StackF, int iNumFrames)
  307.         {
  308.            
  309.             int iRetVal = 0;
  310.             string PackageName = "System.Diagnostics";
  311.            
  312.             // Check if this method is part of the System.Diagnostics
  313.             // package. If so, increment counter keeping track of
  314.             // System.Diagnostics functions
  315.             for (int i = 0; i < iNumFrames; i++) {
  316.                 MethodBase mb = StackF.GetMethodBase(i);
  317.                 if (mb != null) {
  318.                     Type t = mb.DeclaringType;
  319.                     if (t == null)
  320.                         break;
  321.                     string ns = t.Namespace;
  322.                     if (ns == null)
  323.                         break;
  324.                     if (String.Compare(ns, PackageName, StringComparison.Ordinal) != 0)
  325.                         break;
  326.                 }
  327.                 iRetVal++;
  328.             }
  329.            
  330.             return iRetVal;
  331.         }
  332.        
  333.         // Retrieves an object with stack trace information encoded.
  334.         // It leaves out the first "iSkip" lines of the stacktrace.
  335.         //
  336.         private void CaptureStackTrace(int iSkip, bool fNeedFileInfo, Thread targetThread, Exception e)
  337.         {
  338.             m_iMethodsToSkip += iSkip;
  339.            
  340.             StackFrameHelper StackF = new StackFrameHelper(fNeedFileInfo, targetThread);
  341.            
  342.             GetStackFramesInternal(StackF, 0, e);
  343.            
  344.             m_iNumOfFrames = StackF.GetNumberOfFrames();
  345.            
  346.             if (m_iMethodsToSkip > m_iNumOfFrames)
  347.                 m_iMethodsToSkip = m_iNumOfFrames;
  348.            
  349.             if (m_iNumOfFrames != 0) {
  350.                 frames = new StackFrame[m_iNumOfFrames];
  351.                
  352.                 for (int i = 0; i < m_iNumOfFrames; i++) {
  353.                     bool fDummy1 = true;
  354.                     bool fDummy2 = true;
  355.                     StackFrame sfTemp = new StackFrame(fDummy1, fDummy2);
  356.                    
  357.                     sfTemp.SetMethodBase(StackF.GetMethodBase(i));
  358.                     sfTemp.SetOffset(StackF.GetOffset(i));
  359.                     sfTemp.SetILOffset(StackF.GetILOffset(i));
  360.                    
  361.                     if (fNeedFileInfo) {
  362.                         sfTemp.SetFileName(StackF.GetFilename(i));
  363.                         sfTemp.SetLineNumber(StackF.GetLineNumber(i));
  364.                         sfTemp.SetColumnNumber(StackF.GetColumnNumber(i));
  365.                     }
  366.                    
  367.                     frames[i] = sfTemp;
  368.                 }
  369.                
  370.                 // CalculateFramesToSkip skips all frames in the System.Diagnostics namespace,
  371.                 // but this is not desired if building a stack trace from an exception.
  372.                 if (e == null)
  373.                     m_iMethodsToSkip += CalculateFramesToSkip(StackF, m_iNumOfFrames);
  374.                
  375.                 m_iNumOfFrames -= m_iMethodsToSkip;
  376.                 if (m_iNumOfFrames < 0) {
  377.                     m_iNumOfFrames = 0;
  378.                 }
  379.             }
  380.             else
  381.                
  382.                 // In case this is the same object being re-used, set frames to null
  383.                 frames = null;
  384.         }
  385.        
  386.         // Property to get the number of frames in the stack trace
  387.         //
  388.         public virtual int FrameCount {
  389.             get { return m_iNumOfFrames; }
  390.         }
  391.        
  392.        
  393.         // Returns a given stack frame. Stack frames are numbered starting at
  394.         // zero, which is the last stack frame pushed.
  395.         //
  396.         public virtual StackFrame GetFrame(int index)
  397.         {
  398.             if ((frames != null) && (index < m_iNumOfFrames) && (index >= 0))
  399.                 return frames[index + m_iMethodsToSkip];
  400.            
  401.             return null;
  402.         }
  403.        
  404.         // Returns an array of all stack frames for this stacktrace.
  405.         // The array is ordered and sized such that GetFrames()[i] == GetFrame(i)
  406.         // The nth element of this array is the same as GetFrame(n).
  407.         // The length of the array is the same as FrameCount.
  408.         //
  409.         [ComVisible(false)]
  410.         public virtual StackFrame[] GetFrames()
  411.         {
  412.             if (frames == null || m_iNumOfFrames <= 0)
  413.                 return null;
  414.            
  415.             StackFrame[] array = new StackFrame[m_iNumOfFrames];
  416.             Array.Copy(frames, m_iMethodsToSkip, array, 0, m_iNumOfFrames);
  417.             return array;
  418.         }
  419.        
  420.         // Builds a readable representation of the stack trace
  421.         //
  422.         public override string ToString()
  423.         {
  424.             // Include a trailing newline for backwards compatibility
  425.             return ToString(TraceFormat.TrailingNewLine);
  426.         }
  427.        
  428.         // TraceFormat is Used to specify options for how the
  429.         // string-representation of a StackTrace should be generated.
  430.         internal enum TraceFormat
  431.         {
  432.             Normal,
  433.             TrailingNewLine,
  434.             // include a trailing new line character
  435.             NoResourceLookup
  436.             // to prevent infinite resource recusion
  437.         }
  438.        
  439.         // Builds a readable representation of the stack trace, specifying
  440.         // the format for backwards compatibility.
  441.         internal string ToString(TraceFormat traceFormat)
  442.         {
  443.             string word_At = "at";
  444.             string inFileLineNum = "in {0}:line {1}";
  445.            
  446.             if (traceFormat != TraceFormat.NoResourceLookup) {
  447.                 word_At = Environment.GetResourceString("Word_At");
  448.                 inFileLineNum = Environment.GetResourceString("StackTrace_InFileLineNumber");
  449.             }
  450.            
  451.             bool fFirstFrame = true;
  452.             StringBuilder sb = new StringBuilder(255);
  453.             for (int iFrameIndex = 0; iFrameIndex < m_iNumOfFrames; iFrameIndex++) {
  454.                 StackFrame sf = GetFrame(iFrameIndex);
  455.                 MethodBase mb = sf.GetMethod();
  456.                 if (mb != null) {
  457.                     // We want a newline at the end of every line except for the last
  458.                     if (fFirstFrame)
  459.                         fFirstFrame = false;
  460.                     else
  461.                         sb.Append(Environment.NewLine);
  462.                    
  463.                     sb.AppendFormat(CultureInfo.InvariantCulture, " {0} ", word_At);
  464.                    
  465.                     Type t = mb.DeclaringType;
  466.                     // if there is a type (non global method) print it
  467.                     if (t != null) {
  468.                         sb.Append(t.FullName.Replace('+', '.'));
  469.                         sb.Append(".");
  470.                     }
  471.                     sb.Append(mb.Name);
  472.                    
  473.                     // deal with the generic portion of the method
  474.                     if (mb is MethodInfo && ((MethodInfo)mb).IsGenericMethod) {
  475.                         Type[] typars = ((MethodInfo)mb).GetGenericArguments();
  476.                         sb.Append("[");
  477.                         int k = 0;
  478.                         bool fFirstTyParam = true;
  479.                         while (k < typars.Length) {
  480.                             if (fFirstTyParam == false)
  481.                                 sb.Append(",");
  482.                             else
  483.                                 fFirstTyParam = false;
  484.                            
  485.                             sb.Append(typars[k].Name);
  486.                             k++;
  487.                         }
  488.                         sb.Append("]");
  489.                     }
  490.                    
  491.                     // arguments printing
  492.                     sb.Append("(");
  493.                     ParameterInfo[] pi = mb.GetParameters();
  494.                     bool fFirstParam = true;
  495.                     for (int j = 0; j < pi.Length; j++) {
  496.                         if (fFirstParam == false)
  497.                             sb.Append(", ");
  498.                         else
  499.                             fFirstParam = false;
  500.                        
  501.                         string typeName = "<UnknownType>";
  502.                         if (pi[j].ParameterType != null)
  503.                             typeName = pi[j].ParameterType.Name;
  504.                         sb.Append(typeName + " " + pi[j].Name);
  505.                     }
  506.                     sb.Append(")");
  507.                    
  508.                     // source location printing
  509.                     if (sf.GetILOffset() != -1) {
  510.                         // It's possible we have a debug version of an executable but no PDB. In
  511.                         // this case, the file name will be null.
  512.                         string fileName = null;
  513.                        
  514.                         try {
  515.                             fileName = sf.GetFileName();
  516.                         }
  517.                         catch (SecurityException) {
  518.                         }
  519.                        
  520.                         if (fileName != null) {
  521.                             // tack on " in c:\tmp\MyFile.cs:line 5"
  522.                             sb.Append(' ');
  523.                             sb.AppendFormat(CultureInfo.InvariantCulture, inFileLineNum, fileName, sf.GetFileLineNumber());
  524.                         }
  525.                     }
  526.                    
  527.                 }
  528.             }
  529.            
  530.             if (traceFormat == TraceFormat.TrailingNewLine)
  531.                 sb.Append(Environment.NewLine);
  532.            
  533.             return sb.ToString();
  534.         }
  535.        
  536.         // This helper is called from within the EE to construct a string representation
  537.         // of the current stack trace.
  538.         private static string GetManagedStackTraceStringHelper(bool fNeedFileInfo)
  539.         {
  540.             // Note all the frames in System.Diagnostics will be skipped when capturing
  541.             // a normal stack trace (not from an exception) so we don't need to explicitly
  542.             // skip the GetManagedStackTraceStringHelper frame.
  543.             StackTrace st = new StackTrace(0, fNeedFileInfo);
  544.             return st.ToString();
  545.         }
  546.     }
  547.    
  548. }

Developer Fusion