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

DeveloperExperience.cs « DeveloperExperience « Internal « src « System.Private.CoreLib « src - github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: c507307c615761f1331b377763f85b911554c426 (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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// 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.Text;
using System.Runtime;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Reflection;

using Internal.Runtime.Augments;

namespace Internal.DeveloperExperience
{
    [System.Runtime.CompilerServices.ReflectionBlocked]
    public class DeveloperExperience
    {
        /// <summary>
        /// Check the AppCompat switch 'Diagnostics.DisableMetadataStackTraceResolution'.
        /// Some customers use DIA-based tooling to translate stack traces in the raw format
        /// (module)+RVA - for them, stack trace and reflection metadata-based resolution
        /// constitutes technically a regression because these two resolution methods today cannot
        /// provide file name and line number information; PDB-based tooling can easily do that
        /// based on the RVA information.
        ///
        /// Note: a related switch 'Diagnostics.DisableDiaStackTraceResolution' controls whether
        /// runtime may try to use DIA for PDB-based stack frame resolution.
        /// </summary>
        private static bool IsMetadataStackTraceResolutionDisabled()
        {
            bool disableMetadata = false;
            AppContext.TryGetSwitch("Diagnostics.DisableMetadataStackTraceResolution", out disableMetadata);
            return disableMetadata;
        }

        public virtual void WriteLine(string s)
        {
            Debug.WriteLine(s);
            return;
        }

        public virtual string CreateStackTraceString(IntPtr ip, bool includeFileInfo)
        {
            if (!IsMetadataStackTraceResolutionDisabled())
            {
                StackTraceMetadataCallbacks stackTraceCallbacks = RuntimeAugments.StackTraceCallbacksIfAvailable;
                if (stackTraceCallbacks != null)
                {
                    IntPtr methodStart = RuntimeImports.RhFindMethodStartAddress(ip);
                    if (methodStart != IntPtr.Zero)
                    {
                        string methodName = stackTraceCallbacks.TryGetMethodNameFromStartAddress(methodStart);
                        if (methodName != null)
                        {
                            if (ip != methodStart)
                            {
                                methodName += " + 0x" + (ip.ToInt64() - methodStart.ToInt64()).ToString("x");
                            }
                            return methodName;
                        }
                    }
                }
            }

            // If we don't have precise information, try to map it at least back to the right module.
            IntPtr moduleBase = RuntimeImports.RhGetOSModuleFromPointer(ip);
            string moduleFullFileName = RuntimeAugments.TryGetFullPathToApplicationModule(moduleBase);

            // Without any callbacks or the ability to map ip correctly we better admit that we don't know
            if (string.IsNullOrEmpty(moduleFullFileName))
            {
                return "<unknown>";
            }

            StringBuilder sb = new StringBuilder();
            string fileNameWithoutExtension = GetFileNameWithoutExtension(moduleFullFileName);
            int rva = RuntimeAugments.ConvertIpToRva(ip);
            sb.Append(fileNameWithoutExtension);
            sb.Append("!<BaseAddress>+0x");
            sb.Append(rva.ToString("x"));
            return sb.ToString();
        }

        public virtual void TryGetSourceLineInfo(IntPtr ip, out string fileName, out int lineNumber, out int columnNumber)
        {
            fileName = null;
            lineNumber = 0;
            columnNumber = 0;
        }

        public virtual void TryGetILOffsetWithinMethod(IntPtr ip, out int ilOffset)
        {
            ilOffset = StackFrame.OFFSET_UNKNOWN;
        }

        /// <summary>
        /// Makes reasonable effort to get the MethodBase reflection info. Returns null if it can't.
        /// </summary>
        public virtual void TryGetMethodBase(IntPtr methodStartAddress, out MethodBase method)
        {
            ReflectionExecutionDomainCallbacks reflectionCallbacks = RuntimeAugments.CallbacksIfAvailable;
            method = null;
            if (reflectionCallbacks != null)
            {
                method = reflectionCallbacks.GetMethodBaseFromStartAddressIfAvailable(methodStartAddress);
            }
        }

        public virtual bool OnContractFailure(string stackTrace, ContractFailureKind contractFailureKind, string displayMessage, string userMessage, string conditionText, Exception innerException)
        {
            Debug.WriteLine("Assertion failed: " + (displayMessage == null ? "" : displayMessage));
            if (Debugger.IsAttached)
                Debugger.Break();
            return false;
        }

        public static DeveloperExperience Default
        {
            get
            {
                DeveloperExperience result = s_developerExperience;
                if (result == null)
                    return new DeveloperExperience(); // Provide the bare-bones default if a custom one hasn't been supplied.
                return result;
            }

            set
            {
                s_developerExperience = value;
            }
        }

        private static string GetFileNameWithoutExtension(string path)
        {
            path = GetFileName(path);
            int i;
            if ((i = path.LastIndexOf('.')) == -1)
                return path; // No path extension found
            else
                return path.Substring(0, i);
        }

        private static string GetFileName(string path)
        {
            int length = path.Length;
            for (int i = length; --i >= 0;)
            {
                char ch = path[i];
                if (ch == '/' || ch == '\\' || ch == ':')
                    return path.Substring(i + 1, length - i - 1);
            }
            return path;
        }

        private static DeveloperExperience s_developerExperience;
    }
}