Welcome to mirror list, hosted at ThFree Co, Russian Federation.

StackFrame.CoreRT.cs « Diagnostics « System « src « System.Private.CoreLib « src - github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 31a0da58d92f979909a3b9506b7263fe3b13b673 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// 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;
using System.Reflection;
using System.Runtime;
using System.Text;

using Internal.DeveloperExperience;
using Internal.Diagnostics;

namespace System.Diagnostics
{
    /// <summary>
    /// Stack frame represents a single frame in a stack trace; frames
    /// corresponding to methods with available symbolic information
    /// provide source file / line information. Some frames may provide IL
    /// offset information and / or MethodBase reflection information.
    /// There is no good reason for the methods of this class to be virtual.
    /// </summary>
    public partial class StackFrame
    {
        /// <summary>
        /// IP address representing this stack frame.
        /// </summary>
        private IntPtr _ipAddress;

        /// <summary>
        /// File info flag to use for stack trace-style formatting.
        /// </summary>
        private bool _needFileInfo;

        /// <summary>
        /// Constructs a StackFrame corresponding to a given IP address.
        /// </summary>
        internal StackFrame(IntPtr ipAddress, bool needFileInfo)
        {
            InitializeForIpAddress(ipAddress, needFileInfo);
        }

        /// <summary>
        /// Internal stack frame initialization based on IP address.
        /// </summary>
        private void InitializeForIpAddress(IntPtr ipAddress, bool needFileInfo)
        {
            _ipAddress = ipAddress;
            _needFileInfo = needFileInfo;
            
            if (_ipAddress == StackTraceHelper.SpecialIP.EdiSeparator)
            {
                SetIsLastFrameFromForeignExceptionStackTrace(true);
            }
            else if (_ipAddress != IntPtr.Zero)
            {
                IntPtr methodStartAddress = RuntimeImports.RhFindMethodStartAddress(ipAddress);

                _nativeOffset = (int)(_ipAddress.ToInt64() - methodStartAddress.ToInt64());

                DeveloperExperience.Default.TryGetILOffsetWithinMethod(_ipAddress, out _ilOffset);
                DeveloperExperience.Default.TryGetMethodBase(methodStartAddress, out _method);

                if (needFileInfo)
                {
                    DeveloperExperience.Default.TryGetSourceLineInfo(
                        _ipAddress,
                        out _fileName,
                        out _lineNumber,
                        out _columnNumber);
                }
            }
        }

        /// <summary>
        /// Internal stack frame initialization based on frame index within the stack of the current thread.
        /// </summary>
        private void BuildStackFrame(int frameIndex, bool needFileInfo)
        {
            IntPtr ipAddress = LocateIpAddressForStackFrame(frameIndex);
            InitializeForIpAddress(ipAddress, needFileInfo);
        }
        
        /// <summary>
        /// Locate IP address corresponding to a given frame. Ignore .NET Native-specific rethrow markers.
        /// </summary>
        private IntPtr LocateIpAddressForStackFrame(int frameIndex)
        {
            IntPtr[] frameArray = new IntPtr[frameIndex + 1];
            int returnedFrameCount = RuntimeImports.RhGetCurrentThreadStackTrace(frameArray);
            int realFrameCount = (returnedFrameCount >= 0 ? returnedFrameCount : frameArray.Length);
            if (frameIndex < realFrameCount)
            {
                return frameArray[frameIndex];
            }

            // No more frames are available
            return IntPtr.Zero;
        }

        /// <summary>
        /// Return native IP address for this stack frame.
        /// </summary>
        internal IntPtr GetNativeIPAddress()
        {
            return _ipAddress;
        }

        /// <summary>
        /// Check whether method info is available.
        /// </summary>
        internal bool HasMethod()
        {
            return _method != null;
        }

        /// <summary>
        /// Format stack frame without MethodBase info. Return true if the stack info
        /// is valid and line information should be appended if available.
        /// </summary>
        private bool AppendStackFrameWithoutMethodBase(StringBuilder builder)
        {
            builder.Append(DeveloperExperience.Default.CreateStackTraceString(_ipAddress, includeFileInfo: false));
            return true;
        }

        /// <summary>
        /// Builds a representation of the stack frame for use in the stack trace.
        /// </summary>
        internal void AppendToStackTrace(StringBuilder builder)
        {
            if (_ipAddress != StackTraceHelper.SpecialIP.EdiSeparator)
            {
                builder.Append(SR.StackTrace_AtWord);
                builder.AppendLine(DeveloperExperience.Default.CreateStackTraceString(_ipAddress, _needFileInfo));
            }
            if (GetIsLastFrameFromForeignExceptionStackTrace())
            {
                builder.AppendLine(SR.StackTrace_EndStackTraceFromPreviousThrow);
            }
        }
    }
}