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); }
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}"); } }
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); }
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"); } }
/// <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()); }
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); }
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); }
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(""); } }
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"); } }
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")); }