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);
        }
        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);
        }
Beispiel #3
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}");
        }
    }
Beispiel #4
0
        private ThreadPoolItem GetQueueUserWorkItemCallback(ClrObject element)
        {
            ThreadPoolItem tpi = new ThreadPoolItem()
            {
                Address = (ulong)element,
                Type    = ThreadRoot.WorkItem
            };

            // look for the callback given to ThreadPool.QueueUserWorkItem()
            // for .NET Core, the callback is stored in a different field _callback
            var       elementType = element.Type;
            ClrObject callback;

            if (elementType.GetFieldByName("_callback") != null)
            {
                callback = element.ReadObjectField("_callback");
            }
            else if (elementType.GetFieldByName("callback") != null)
            {
                callback = element.ReadObjectField("callback");
            }
            else
            {
                tpi.MethodName = "[no callback]";
                return(tpi);
            }

            var target = callback.ReadObjectField("_target");

            if (!target.IsValid)
            {
                tpi.MethodName = "[no callback target]";
                return(tpi);
            }

            ClrType targetType = target.Type;

            if (targetType == null)
            {
                tpi.MethodName = $" [target=0x{target.Address}]";
            }
            else
            {
                // look for method name
                tpi.MethodName = BuildDelegateMethodName(targetType, callback);
            }

            return(tpi);
        }
        private int GetActiveConnectionCount(ClrObject connectionPool)
        {
            var      connections           = connectionPool.ReadObjectField("_objectList");
            ClrArray dbConnectionInternals = connections.ReadObjectField("_items").AsArray();
            int      openConnections       = 0;

            for (int i = 0; i < dbConnectionInternals.Length; i++)
            {
                var  SqlInternalConnectionTds = dbConnectionInternals.GetObjectValue(i);
                bool isConnectioOpen          = false;
                try
                {
                    isConnectioOpen = SqlInternalConnectionTds.ReadField <bool>("_fConnectionOpen");
                }
                catch (Exception e)
                {
                    PrintDebugMessage($"Exception while processing active connections {e.Message}");
                    //the array can have null objects. We will be catching them here.
                }
                if (isConnectioOpen)
                {
                    openConnections++;
                }
            }
            return(openConnections);
        }
Beispiel #6
0
        private IEnumerable <TimerInfo> GetTimers(ClrObject timerQueueTimer, bool is30Format)
        {
            while (timerQueueTimer.Address != 0)
            {
                var ti = GetTimerInfo(timerQueueTimer);
                if (ti == null)
                {
                    continue;
                }

                yield return(ti);

                timerQueueTimer = is30Format ?
                                  timerQueueTimer.ReadObjectField("_next") :
                                  timerQueueTimer.ReadObjectField("m_next");
            }
        }
Beispiel #7
0
        /// <summary>
        /// This only works starting from .NET 5
        /// https://github.com/dotnet/runtime/issues/11157
        /// TODO: compute the field from the property name
        /// </summary>
        /// <param name="allocatorObject"></param>
        /// <returns></returns>
        public string GetAllocatorName(ClrObject allocatorObject)
        {
            // allocatorObject is AssemblyLoadContext or a derived class
            // this means it has a property called "Name"
            var value = allocatorObject.ReadObjectField("_name");

            return(value.GetStringValue());
        }
Beispiel #8
0
        private ThreadPoolItem GetTask(ClrObject task)
        {
            ThreadPoolItem tpi = new ThreadPoolItem()
            {
                Address = task.Address,
                Type    = ThreadRoot.Task
            };

            // look for the context in m_action._target
            var action = task.ReadObjectField("m_action");

            if (!action.IsValid)
            {
                tpi.MethodName = " [no action]";
                return(tpi);
            }

            var target = action.ReadObjectField("_target");

            if (!target.IsValid)
            {
                tpi.MethodName = " [no target]";
                return(tpi);
            }

            tpi.MethodName = BuildDelegateMethodName(target.Type, action);

            // get the task scheduler if any
            var taskScheduler = task.ReadObjectField("m_taskScheduler");

            if (taskScheduler.IsValid)
            {
                var schedulerType = taskScheduler.Type.ToString();
                if (string.CompareOrdinal("System.Threading.Tasks.ThreadPoolTaskScheduler", schedulerType) != 0)
                {
                    tpi.MethodName = $"{tpi.MethodName} [{schedulerType}]";
                }
            }
            return(tpi);
        }
Beispiel #9
0
        private IEnumerable <ThreadPoolItem> EnumerateThreadPoolStealingQueue(ClrObject stealingQueue)
        {
            var array = stealingQueue.ReadObjectField("m_array").AsArray();

            for (int current = 0; current < array.Length; current++)
            {
                var item = array.GetObjectValue(current);
                if (!item.IsValid)
                {
                    continue;
                }

                yield return(GetThreadPoolItem(item));
            }
        }
        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);
        }
Beispiel #11
0
        public void EnumerateGCRefsArray()
        {
            using DataTarget dataTarget = TestTargets.GCRoot.LoadFullDump();
            using ClrRuntime runtime    = dataTarget.ClrVersions.Single().CreateRuntime();
            ClrHeap heap = runtime.Heap;

            ClrModule module   = heap.Runtime.GetMainModule();
            ClrType   mainType = module.GetTypeByName("GCRootTarget");

            ClrObject obj = mainType.GetStaticObjectValue("TheRoot");

            obj = obj.ReadObjectField("Item1");

            Assert.Equal("System.Object[]", obj.Type.Name);

            ClrObject[] refs = obj.EnumerateReferences(false).ToArray();
            obj = Assert.Single(refs);
            Assert.Equal("DoubleRef", obj.Type.Name);
        }
        private IEnumerable <SqlCommandInfo> GetSqlCommandInfo()
        {
            List <ClrObject> commandObjects = new List <ClrObject>();

            commandObjects.AddRange(FilterObjectByType("System.Data.SqlClient.SqlCommand"));
            commandObjects.AddRange(FilterObjectByType("Microsoft.Data.SqlClient.SqlCommand"));

            if (commandObjects.Count != 0)
            {
                foreach (ClrObject commandObject in commandObjects)
                {
                    string    commandString    = commandObject.ReadStringField("_commandText");
                    string    connectionString = commandObject.ReadObjectField("_activeConnection").ReadStringField("_connectionString");
                    ClrObject paramsObject     = commandObject.ReadObjectField("_parameters");
                    int       connState        = commandObject.ReadObjectField("_activeConnection").ReadObjectField("_innerConnection").ReadField <int>("_state");
                    string    connectionState  = "Open";
                    if (connState == 0)
                    {
                        connectionState = "Closed";
                    }

                    Dictionary <string, string> parameters = new Dictionary <string, string>();
                    if (paramsObject.Address != 0)
                    {
                        ClrArray paramsArray = paramsObject.ReadObjectField("_items").ReadObjectField("_items").AsArray();
                        parameters = GetParameters(paramsArray);
                    }

                    yield return(parameters.Count == 0
                        ? new SqlCommandInfo {
                        CommandString = commandString, ConnectionString = connectionString, Parameters = null, ConnectionState = connectionState
                    }
                        : new SqlCommandInfo {
                        CommandString = commandString, ConnectionString = commandString, Parameters = parameters, ConnectionState = connectionState
                    });
                }
            }
            else
            {
                yield break;
            }
        }
        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("");
            }
        }
Beispiel #14
0
        private IEnumerable <ThreadPoolItem> EnumerateThreadPoolWorkQueue(ClrObject workQueue)
        {
            // start from the tail and follow the Next
            var currentQueueSegment = workQueue.ReadObjectField("queueTail");

            while (currentQueueSegment.IsValid)
            {
                // get the System.Threading.ThreadPoolWorkQueue+QueueSegment nodes array
                var nodes = currentQueueSegment.ReadObjectField("nodes").AsArray();
                for (int currentNode = 0; currentNode < nodes.Length; currentNode++)
                {
                    var item = nodes.GetObjectValue(currentNode);
                    if (!item.IsValid)
                    {
                        continue;
                    }

                    yield return(GetThreadPoolItem(item));
                }

                currentQueueSegment = currentQueueSegment.ReadObjectField("Next");
            }
        }
Beispiel #15
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);
        }
 private ClrObject GetPerformanceObject(ClrObject obj, string counterName)
 {
     return(obj.ReadObjectField(counterName).Address == 0 || obj.ReadObjectField(counterName).ReadObjectField("_instance").Address == 0
         ? throw new ArgumentNullException()
         : obj.ReadObjectField(counterName).ReadObjectField("_instance").ReadObjectField("sharedCounter"));
 }