Пример #1
0
        private TimerInfo GetTimerInfo(ClrObject currentTimerQueueTimer)
        {
            var ti = new TimerInfo()
            {
                TimerQueueTimerAddress = currentTimerQueueTimer.Address
            };

            ti.DueTime   = currentTimerQueueTimer.ReadField <uint>("m_dueTime");
            ti.Period    = currentTimerQueueTimer.ReadField <uint>("m_period");
            ti.Cancelled = currentTimerQueueTimer.ReadField <bool>("m_canceled");

            var state = currentTimerQueueTimer.ReadObjectField("m_state");

            ti.StateAddress = 0;
            if (state.IsValid)
            {
                ti.StateAddress = state.Address;
                var stateType = _heap.GetObjectType(ti.StateAddress);
                if (stateType != null)
                {
                    ti.StateTypeName = stateType.Name;
                }
            }

            // decipher the callback details
            var timerCallback = currentTimerQueueTimer.ReadObjectField("m_timerCallback");

            if (timerCallback.IsValid)
            {
                var elementType = timerCallback.Type;
                if (elementType != null)
                {
                    if (elementType.Name == "System.Threading.TimerCallback")
                    {
                        ti.MethodName = BuildTimerCallbackMethodName(timerCallback);
                    }
                    else
                    {
                        ti.MethodName = "<" + elementType.Name + ">";
                    }
                }
                else
                {
                    ti.MethodName = "{no callback type?}";
                }
            }
            else
            {
                ti.MethodName = "???";
            }


            return(ti);
        }
Пример #2
0
        private Dictionary <string, string> GetParameters(ClrArray parameters)
        {
            Dictionary <string, string> parameterValues = new Dictionary <string, string>();

            for (int i = 0; i < parameters.Length; i++)
            {
                ClrObject parameter = parameters.GetObjectValue(i);
                if (parameter.Address != 0)
                {
                    string parameterName  = parameter.ReadStringField("_parameterName");
                    string parameterValue = "";
                    if (parameter.ReadObjectField("_value").Address != 0)
                    {
                        switch (parameter.ReadObjectField("_value").Type.Name)
                        {
                        case "System.Int64":
                            parameterValue = parameter.ReadField <Int64>("_value").ToString();
                            break;

                        case "System.String":
                            parameterValue = parameter.ReadObjectField("_value").AsString();
                            break;

                        case "System.Int32":
                            parameterValue = parameter.ReadField <Int32>("_value").ToString();
                            break;

                        case "System.DateTime":
                            parameterValue = parameter.ReadField <DateTime>("_value").ToString();
                            break;

                        case "System.Double":
                            parameterValue = parameter.ReadField <Double>("_value").ToString();
                            break;

                        case "System.Boolean":
                            parameterValue = parameter.ReadField <Boolean>("_value").ToString();
                            break;

                        default:
                            parameterValue = "cannot be read";
                            break;
                        }
                    }

                    if (!string.IsNullOrEmpty(parameterValue) && !string.IsNullOrEmpty(parameterName))
                    {
                        parameterValues.Add(parameterName, parameterValue);
                    }
                }
            }
            return(parameterValues);
        }
Пример #3
0
        private (string connectionString, int maxPoolSize, int minPoolSize) GetConnectionStringDetails(ClrObject connectionPool)
        {
            string connectionString;

            ClrObject poolGroup   = connectionPool.ReadObjectField("_connectionPoolGroup");
            ClrObject poolOptions = poolGroup.ReadObjectField("_connectionOptions");

            connectionString = poolOptions.ReadStringField("_usersConnectionString");

            int maxPoolSize = poolOptions.ReadField <int>("_maxPoolSize");

            int minPoolSize = poolOptions.ReadField <int>("_minPoolSize");

            return(connectionString, maxPoolSize, minPoolSize);
        }
Пример #4
0
        private static TaskStatus GetStatus(ClrObject taskObject)
        {
            var stateFlags = taskObject.ReadField <int>("m_stateFlags");

            if ((stateFlags & TaskStateFaulted) != 0)
            {
                return(TaskStatus.Faulted);
            }
            if ((stateFlags & TaskStateCanceled) != 0)
            {
                return(TaskStatus.Canceled);
            }
            if ((stateFlags & TaskStateRanToCompletion) != 0)
            {
                return(TaskStatus.RanToCompletion);
            }
            if ((stateFlags & TaskStateWaitingOnChildren) != 0)
            {
                return(TaskStatus.WaitingForChildrenToComplete);
            }
            if ((stateFlags & TaskStateDelegateInvoked) != 0)
            {
                return(TaskStatus.Running);
            }
            if ((stateFlags & TaskStateStarted) != 0)
            {
                return(TaskStatus.WaitingToRun);
            }
            if ((stateFlags & TaskStateWaitingForActivation) != 0)
            {
                return(TaskStatus.WaitingForActivation);
            }

            return(TaskStatus.Created);
        }
Пример #5
0
        internal string BuildDelegateMethodName(ClrType targetType, ClrObject action)
        {
            var methodPtr = action.ReadField <ulong>("_methodPtr");

            if (methodPtr != 0)
            {
                ClrMethod method = _clr.GetMethodByInstructionPointer(methodPtr);
                if (method == null)
                {
                    // could happen in case of static method
                    methodPtr = action.ReadField <ulong>("_methodPtrAux");
                    method    = _clr.GetMethodByInstructionPointer(methodPtr);
                }

                if (method != null)
                {
                    // anonymous method
                    if (method.Type.Name == targetType.Name)
                    {
                        return($"{targetType.Name}.{method.Name}");
                    }
                    else
                    // method is implemented by an class inherited from targetType
                    // ... or a simple delegate indirection to a static/instance method
                    {
                        if (
                            (string.CompareOrdinal(targetType.Name, "System.Threading.WaitCallback") == 0) ||
                            targetType.Name.StartsWith("System.Action<", StringComparison.Ordinal)
                            )
                        {
                            return($"{method.Type.Name}.{method.Name}");
                        }
                        else
                        {
                            return($"({targetType.Name}){method.Type.Name}.{method.Name}");
                        }
                    }
                }
            }

            return("");
        }
Пример #6
0
    static void Main(string[] args)
    {
        if (args.Length != 3)
        {
            Console.WriteLine("Usage: DumpDict [dump] [objref]");
            Environment.Exit(1);
        }

        if (ulong.TryParse(args[2], System.Globalization.NumberStyles.HexNumber, null, out ulong objAddr))
        {
            Console.WriteLine($"Could not parse object ref '{args[2]}'.");
            Environment.Exit(1);
        }

        string dumpFileName = args[0];
        string dacPath      = args[1];

        using DataTarget dataTarget = DataTarget.LoadDump(dumpFileName);
        using ClrRuntime runtime    = dataTarget.ClrVersions.Single().CreateRuntime();
        ClrHeap heap = runtime.Heap;

        ClrObject obj = heap.GetObject(objAddr);

        if (!obj.IsValidObject)
        {
            Console.WriteLine("Invalid object {0:X}", obj);
            return;
        }

        if (!obj.Type.Name.StartsWith("System.Collections.Generic.Dictionary"))
        {
            Console.WriteLine("Error: Expected object {0:X} to be a dictionary, instead it's of type '{1}'.");
            return;
        }

        // Get the entries field.
        ClrArray entries = obj.ReadObjectField("entries").AsArray();

        Console.WriteLine("{0,8} {1,16} : {2}", "hash", "key", "value");
        for (int i = 0; i < entries.Length; ++i)
        {
            ClrObject entry = entries.GetObjectValue(i);

            // TODO: Need to handle non-object references
            int       hashCode = entry.ReadField <int>("hashCode");
            ClrObject key      = entry.ReadObjectField("key");
            ClrObject value    = entry.ReadObjectField("value");

            Console.WriteLine($"{hashCode:x} {key} -> {value}");
        }
    }
Пример #7
0
        private SQLConnectionInfo GetConnectionDetails(ClrObject connectionPool)
        {
            int    maxPoolSize, minPoolSize;
            string connectionString;

            (connectionString, maxPoolSize, minPoolSize) = GetConnectionStringDetails(connectionPool);
            return(new SQLConnectionInfo
            {
                OpenConnectionCount = GetActiveConnectionCount(connectionPool),
                ConnectionString = connectionString,
                CurrentConnectionCount = connectionPool.ReadField <int>("_totalObjects"),
                MaxPoolSize = maxPoolSize,
                MinPoolSize = minPoolSize
            });
        }
Пример #8
0
        private static void MarkThreadingBlockTasks(DebuggerContext context, List <AsyncStateMachine> allStateMachines)
        {
            foreach (var thread in context.Runtime.Threads)
            {
                var stackFrame = thread.EnumerateStackTrace().Take(50).FirstOrDefault(
                    f => f.Method is { } method &&
                    string.Equals(f.Method.Name, "CompleteOnCurrentThread", StringComparison.Ordinal) &&
                    string.Equals(f.Method.Type?.Name, "Microsoft.VisualStudio.Threading.JoinableTask", StringComparison.Ordinal));

                if (stackFrame is object)
                {
                    var visitedObjects = new HashSet <ulong>();
                    foreach (IClrStackRoot stackRoot in thread.EnumerateStackRoots())
                    {
                        ClrObject stackObject = stackRoot.Object;
                        if (string.Equals(stackObject.Type?.Name, "Microsoft.VisualStudio.Threading.JoinableTask", StringComparison.Ordinal) ||
                            string.Equals(stackObject.Type?.BaseType?.Name, "Microsoft.VisualStudio.Threading.JoinableTask", StringComparison.Ordinal))
                        {
                            if (visitedObjects.Add(stackObject.Address))
                            {
                                var joinableTaskObject = new ClrObject(stackObject.Address, stackObject.Type);
                                int state = joinableTaskObject.ReadField <int>("state");
                                if ((state & 0x10) == 0x10)
                                {
                                    // This flag indicates the JTF is blocking the thread
                                    var wrappedTask = joinableTaskObject.TryGetObjectField("wrappedTask");
                                    if (!wrappedTask.IsNull)
                                    {
                                        var blockingStateMachine = allStateMachines
                                                                   .FirstOrDefault(s => s.Task.Address == wrappedTask.Address);
                                        if (blockingStateMachine is object)
                                        {
                                            blockingStateMachine.BlockedThread       = thread.OSThreadId;
                                            blockingStateMachine.BlockedJoinableTask = joinableTaskObject;
                                        }
                                    }

                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #9
0
        private unsafe long GetPerfCounterValue(ClrObject perfCounter)
        {
            if (perfCounter == null)
            {
                return(0);
            }
            ulong       entryPoint = perfCounter.ReadField <ulong>("counterEntryPointer");
            int         v          = sizeof(CounterEntry);
            Span <byte> buffer     = new byte[v];
            int         read       = Target.DataReader.Read(entryPoint, buffer);

            fixed(byte *ptr = buffer)
            {
                CounterEntry counterEntry = *(CounterEntry *)ptr;

                return(counterEntry.Value);
            }
        }
Пример #10
0
        private string BuildTimerCallbackMethodName(ClrObject timerCallback)
        {
            var methodPtr = timerCallback.ReadField <ulong>("_methodPtr");

            if (methodPtr != 0)
            {
                // NOTE: can't find a replacement for ClrMD 1.1 GetMethodByAddress
                // GetMethodByInstructionPointer always returns null
                var method = _clr.GetMethodByInstructionPointer(methodPtr);
                if (method != null)
                {
                    // look for "this" to figure out the real callback implementor type
                    var thisTypeName = "?";
                    var thisPtr      = timerCallback.ReadObjectField("_target");
                    if (thisPtr.IsValid)
                    {
                        var thisRef  = thisPtr.Address;
                        var thisType = _heap.GetObjectType(thisRef);
                        if (thisType != null)
                        {
                            thisTypeName = thisType.Name;
                        }
                    }
                    else
                    {
                        thisTypeName = (method.Type != null) ? method.Type.Name : "?";
                    }
                    return($"{thisTypeName}.{method.Name}");
                }
                else
                {
                    return("");
                }
            }
            else
            {
                return("");
            }
        }
Пример #11
0
        private TimerInfo GetTimerInfo(ClrObject currentTimerQueueTimer)
        {
            var ti = new TimerInfo()
            {
                TimerQueueTimerAddress = currentTimerQueueTimer.Address
            };

            // field names prefix changes from "m_" to "_" in .NET Core 3.0
            var       is30Format = currentTimerQueueTimer.Type.GetFieldByName("_dueTime") != null;
            ClrObject state;

            if (is30Format)
            {
                ti.DueTime   = currentTimerQueueTimer.ReadField <uint>("_dueTime");
                ti.Period    = currentTimerQueueTimer.ReadField <uint>("_period");
                ti.Cancelled = currentTimerQueueTimer.ReadField <bool>("_canceled");
                state        = currentTimerQueueTimer.ReadObjectField("_state");
            }
            else
            {
                ti.DueTime   = currentTimerQueueTimer.ReadField <uint>("m_dueTime");
                ti.Period    = currentTimerQueueTimer.ReadField <uint>("m_period");
                ti.Cancelled = currentTimerQueueTimer.ReadField <bool>("m_canceled");
                state        = currentTimerQueueTimer.ReadObjectField("m_state");
            }

            ti.StateAddress = 0;
            if (state.IsValid)
            {
                ti.StateAddress = state.Address;
                var stateType = _heap.GetObjectType(ti.StateAddress);
                if (stateType != null)
                {
                    ti.StateTypeName = stateType.Name;
                }
            }

            // decipher the callback details
            var timerCallback = is30Format ?
                                currentTimerQueueTimer.ReadObjectField("_timerCallback") :
                                currentTimerQueueTimer.ReadObjectField("m_timerCallback");

            if (timerCallback.IsValid)
            {
                var elementType = timerCallback.Type;
                if (elementType != null)
                {
                    if (elementType.Name == "System.Threading.TimerCallback")
                    {
                        ti.MethodName = BuildTimerCallbackMethodName(timerCallback);
                    }
                    else
                    {
                        ti.MethodName = "<" + elementType.Name + ">";
                    }
                }
                else
                {
                    ti.MethodName = "{no callback type?}";
                }
            }
            else
            {
                ti.MethodName = "???";
            }


            return(ti);
        }
Пример #12
0
        private static void GetAllStateMachines(DebuggerContext context, ClrHeap heap, List <AsyncStateMachine> allStateMachines, Dictionary <ulong, AsyncStateMachine> knownStateMachines)
        {
            foreach (ClrObject obj in heap.GetObjectsOfType("System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner"))
            {
                try
                {
                    ClrObject stateMachine = obj.ReadObjectField("m_stateMachine");
                    if (!knownStateMachines.ContainsKey(stateMachine.Address))
                    {
                        try
                        {
                            var state = stateMachine.ReadField <int>("<>1__state");
                            if (state >= -1)
                            {
                                ClrObject    taskField    = default(ClrObject);
                                ClrValueType?asyncBuilder = stateMachine.TryGetValueClassField("<>t__builder");
                                if (asyncBuilder.HasValue)
                                {
                                    while (asyncBuilder.HasValue)
                                    {
                                        taskField = asyncBuilder.TryGetObjectField("m_task");
                                        if (!taskField.IsNull)
                                        {
                                            break;
                                        }

                                        ClrValueType?nextAsyncBuilder = asyncBuilder.TryGetValueClassField("m_builder");
                                        if (nextAsyncBuilder is null)
                                        {
                                            asyncBuilder = asyncBuilder.TryGetValueClassField("_methodBuilder");
                                        }
                                        else
                                        {
                                            asyncBuilder = nextAsyncBuilder;
                                        }
                                    }
                                }
                                else
                                {
                                    // CLR debugger may not be able to access t__builder, when NGEN assemblies are being used, and the type of the field could be lost.
                                    // Our workaround is to pick up the first Task object referenced by the state machine, which seems to be correct.
                                    // That function works with the raw data structure (like how GC scans the object, so it doesn't depend on symbols.
                                    //
                                    // However, one problem of that is we can pick up tasks from other reference fields of the same structure. So, we go through fields which we have symbols
                                    // and remember references encounted, and we skip them when we go through GC references.
                                    // Note: we can do better by going through other value structures, and extract references from them here, which we can consider when we have a real scenario.
                                    var previousReferences = new Dictionary <ulong, int>();
                                    if (stateMachine.Type?.GetFieldByName("<>t__builder") is not null)
                                    {
                                        foreach (ClrInstanceField field in stateMachine.Type.Fields)
                                        {
                                            if (string.Equals(field.Name, "<>t__builder", StringComparison.Ordinal))
                                            {
                                                break;
                                            }

                                            if (field.IsObjectReference)
                                            {
                                                ClrObject referencedValue = field.ReadObject(stateMachine.Address, interior: false);
                                                if (!referencedValue.IsNull)
                                                {
                                                    if (previousReferences.TryGetValue(referencedValue.Address, out int refCount))
                                                    {
                                                        previousReferences[referencedValue.Address] = refCount + 1;
                                                    }
                                                    else
                                                    {
                                                        previousReferences[referencedValue.Address] = 1;
                                                    }
                                                }
                                            }
                                        }
                                    }

                                    foreach (ClrObject referencedObject in stateMachine.EnumerateReferences(true))
                                    {
                                        if (!referencedObject.IsNull)
                                        {
                                            if (previousReferences.TryGetValue(referencedObject.Address, out int refCount) && refCount > 0)
                                            {
                                                if (refCount == 1)
                                                {
                                                    previousReferences.Remove(referencedObject.Address);
                                                }
                                                else
                                                {
                                                    previousReferences[referencedObject.Address] = refCount - 1;
                                                }

                                                continue;
                                            }
                                            else if (previousReferences.Count > 0)
                                            {
                                                continue;
                                            }

                                            if (referencedObject.Type is object &&
                                                (string.Equals(referencedObject.Type.Name, "System.Threading.Tasks.Task", StringComparison.Ordinal) || string.Equals(referencedObject.Type.BaseType?.Name, "System.Threading.Tasks.Task", StringComparison.Ordinal)))
                                            {
                                                taskField = referencedObject;
                                                break;
                                            }
                                        }
                                    }
                                }

                                var asyncState = new AsyncStateMachine(state, stateMachine, taskField);
                                allStateMachines.Add(asyncState);
                                knownStateMachines.Add(stateMachine.Address, asyncState);

                                if (stateMachine.Type is object)
                                {
                                    foreach (ClrMethod?method in stateMachine.Type.Methods)
                                    {
                                        if (method.Name == "MoveNext" && method.NativeCode != ulong.MaxValue)
                                        {
                                            asyncState.CodeAddress = method.NativeCode;
                                        }
                                    }
                                }
                            }
                        }
#pragma warning disable CA1031 // Do not catch general exception types
                        catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                        {
                            context.Output.WriteLine($"Fail to process state machine {stateMachine.Address:x} Type:'{stateMachine.Type?.Name}' Module:'{stateMachine.Type?.Module?.Name}' Error: {ex.Message}");
                        }
                    }
                }
#pragma warning disable CA1031 // Do not catch general exception types
                catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                {
                    context.Output.WriteLine($"Fail to process AsyncStateMachine Runner {obj.Address:x} Error: {ex.Message}");
                }
            }
        }
Пример #13
0
 private static int GetStateFlags(ClrObject taskObject)
 {
     return(taskObject.ReadField <int>("m_stateFlags"));
 }
Пример #14
0
        private static void GetAllStateMachines(DebuggerContext context, ClrHeap heap, List <AsyncStateMachine> allStateMachines, Dictionary <ulong, AsyncStateMachine> knownStateMachines)
        {
            foreach (ClrObject obj in heap.GetObjectsOfType("System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner"))
            {
                try
                {
                    ClrObject stateMachine = obj.ReadObjectField("m_stateMachine");
                    if (!knownStateMachines.ContainsKey(stateMachine.Address))
                    {
                        try
                        {
                            var state = stateMachine.ReadField <int>("<>1__state");
                            if (state >= -1)
                            {
                                ClrObject    taskField    = default(ClrObject);
                                ClrValueType?asyncBuilder = stateMachine.TryGetValueClassField("<>t__builder");
                                if (asyncBuilder.HasValue)
                                {
                                    while (asyncBuilder.HasValue)
                                    {
                                        taskField = asyncBuilder.TryGetObjectField("m_task");
                                        if (!taskField.IsNull)
                                        {
                                            break;
                                        }

                                        asyncBuilder = asyncBuilder.TryGetValueClassField("m_builder");
                                    }
                                }
                                else
                                {
                                    // CLR debugger may not be able to access t__builder, when NGEN assemblies are being used, and the type of the field could be lost.
                                    // Our workaround is to pick up the first Task object referenced by the state machine, which seems to be correct.
                                    // That function works with the raw data structure (like how GC scans the object, so it doesn't depend on symbols.
                                    foreach (ClrObject referencedObject in stateMachine.EnumerateReferences(true))
                                    {
                                        if (!referencedObject.IsNull && referencedObject.Type is object)
                                        {
                                            if (string.Equals(referencedObject.Type.Name, "System.Threading.Tasks.Task", StringComparison.Ordinal) || string.Equals(referencedObject.Type.BaseType?.Name, "System.Threading.Tasks.Task", StringComparison.Ordinal))
                                            {
                                                taskField = referencedObject;
                                                break;
                                            }
                                        }
                                    }
                                }

                                var asyncState = new AsyncStateMachine(state, stateMachine, taskField);
                                allStateMachines.Add(asyncState);
                                knownStateMachines.Add(stateMachine.Address, asyncState);

                                if (stateMachine.Type is object)
                                {
                                    foreach (ClrMethod?method in stateMachine.Type.Methods)
                                    {
                                        if (method.Name == "MoveNext" && method.NativeCode != ulong.MaxValue)
                                        {
                                            asyncState.CodeAddress = method.NativeCode;
                                        }
                                    }
                                }
                            }
                        }
#pragma warning disable CA1031 // Do not catch general exception types
                        catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                        {
                            context.Output.WriteLine($"Fail to process state machine {stateMachine.Address:x} Type:'{stateMachine.Type?.Name}' Module:'{stateMachine.Type?.Module?.Name}' Error: {ex.Message}");
                        }
                    }
                }
#pragma warning disable CA1031 // Do not catch general exception types
                catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                {
                    context.Output.WriteLine($"Fail to process AsyncStateMachine Runner {obj.Address:x} Error: {ex.Message}");
                }
            }
        }