internal static bool GetStaticField(ClrHeap heap, ClrType type, GetMemberBinder binder, out object result) { result = null; bool success = false; ClrStaticField field = null; StringComparison compare = binder.IgnoreCase ? StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture; foreach (var inst in type.StaticFields) { if (inst.Name.Equals(binder.Name, compare)) { field = inst; break; } } if (field != null) { result = new StaticVariableValueWrapper(heap, field); success = true; } return(success); }
public static ClrObject GetStaticFldValue(this ClrRuntime runtime, [NotNull] ClrType clrType, [NotNull] string fieldName) { Assert.ArgumentNotNull(clrType, "typeName"); Assert.ArgumentNotNullOrEmpty(fieldName, "fieldName"); ClrStaticField fld = clrType.GetStaticFieldByName(fieldName); if (fld == null) { throw new MissingFieldException(clrType.Name, fieldName); } var domains = runtime.AppDomains.ToArray(); if ((domains == null) || (domains.Length == 0)) { throw new ArgumentException("No domains are found inside runtime!"); } ulong?resultAddress = (from domain in domains where !string.IsNullOrWhiteSpace(domain.Name) where !domain.Name.Contains("Default") && fld.IsInitialized(domain) select(ulong?) fld.GetValue(domain)).FirstOrDefault(); return(resultAddress.HasValue ? (new ClrObject(resultAddress.Value, clrType.Heap)) : ClrObject.NullObject); }
public void AsEnumTest() { using DataTarget dt = TestTargets.Types.LoadFullDump(); using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime(); ClrModule typesModule = runtime.GetModule(ModuleName); ClrType type = typesModule.GetTypeByName("Types"); ClrStaticField field = type.GetStaticFieldByName("s_enum"); Assert.True(field.Type.IsEnum); ClrEnum clrEnum = field.Type.AsEnum(); Assert.NotNull(clrEnum); string[] propertyNames = clrEnum.GetEnumNames().ToArray(); Assert.NotEmpty(propertyNames); Assert.Contains(nameof(FileAccess.Read), propertyNames); Assert.Contains(nameof(FileAccess.Write), propertyNames); Assert.Contains(nameof(FileAccess.ReadWrite), propertyNames); Assert.Equal(ClrElementType.Int32, clrEnum.ElementType); Assert.Equal(FileAccess.Read, clrEnum.GetEnumValue <FileAccess>(nameof(FileAccess.Read))); Assert.Equal(FileAccess.Write, clrEnum.GetEnumValue <FileAccess>(nameof(FileAccess.Write))); Assert.Equal(FileAccess.ReadWrite, clrEnum.GetEnumValue <FileAccess>(nameof(FileAccess.ReadWrite))); }
public void IntegerObjectClrType() { using DataTarget dt = TestTargets.Types.LoadFullDump(); using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime(); ClrHeap heap = runtime.Heap; ClrAppDomain domain = runtime.AppDomains.Single(); ClrModule module = runtime.GetModule(ModuleName); ClrType typesType = module.GetTypeByName("Types"); ClrStaticField field = typesType.GetStaticFieldByName("s_i"); ClrObject obj = field.ReadObject(domain); Assert.False(obj.IsNull); ClrType type = obj.Type; Assert.NotNull(type); Assert.True(type.IsPrimitive); Assert.False(type.IsObjectReference); Assert.True(type.IsValueType); var fds = obj.Type.Fields; Assert.True(obj.IsBoxedValue); int value = obj.ReadBoxedValue <int>(); Assert.Equal(42, value); Assert.Contains(obj.Address, heap.EnumerateObjects().Select(a => a.Address)); }
public static ClrObject GetStaticObjectValue(this ClrType mainType, string fieldName) { ClrStaticField field = mainType.GetStaticFieldByName(fieldName); ulong obj = (ulong)field.GetValue(field.Type.Heap.Runtime.AppDomains.Single()); return(new ClrObject(obj, mainType.Heap.GetObjectType(obj))); }
private int GetClrTypeStaticField(Tuple <int, string> input) { int clrTypeId = input.Item1; string fieldName = input.Item2; ClrType clrType = clrTypesCache[clrTypeId]; ClrStaticField clrStaticField = clrType.GetStaticFieldByName(fieldName); return(GetClrTypeId(clrStaticField?.Type)); }
public StaticField(ClrRuntime runtime, string typee, string name) { Domain = runtime.AppDomains.First(); ClrHeap heap = runtime.GetHeap(); ClrType type = heap.GetTypeByName(typee); Field = type.GetStaticFieldByName(name); Heap = runtime.GetHeap(); }
private ulong GetClrStaticFieldAddress(Tuple <int, string, int> input) { int clrTypeId = input.Item1; string fieldName = input.Item2; int clrAppDomainId = input.Item3; ClrType clrType = clrTypesCache[clrTypeId]; ClrStaticField clrStaticField = clrType.GetStaticFieldByName(fieldName); ClrAppDomain clrAppDomain = clrType.Module.Runtime.AppDomains.First(ad => ad.Id == clrAppDomainId); return(clrStaticField.GetAddress(clrAppDomain)); }
public NetFrameworkClrDriver(ClrRuntime runtime) : base(runtime) { typeTimerQueue = heap.GetTypeByName("System.Threading.TimerQueue"); fieldSQueue = typeTimerQueue.GetStaticFieldByName("s_queue"); fieldTimers = typeTimerQueue.GetFieldByName("m_timers"); typeTimerQueueTimer = heap.GetTypeByName("System.Threading.TimerQueueTimer"); fieldNext = typeTimerQueueTimer.GetFieldByName("m_next"); fieldState = typeTimerQueueTimer.GetFieldByName("m_state"); typeMoveNextRunner = heap.GetTypeByName("System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner"); fieldStateMachine = typeMoveNextRunner.GetFieldByName("m_stateMachine"); }
/// <summary> /// Initializes a new instance of the <see cref="ClrStaticFieldAdapter" /> class. /// </summary> /// <param name="converter">Converter to use</param> /// <param name="staticField">The static field.</param> /// <exception cref="ArgumentNullException">staticField</exception> /// <inheritdoc /> public ClrStaticFieldAdapter(IConverter converter, ClrStaticField staticField) : base(converter) { StaticField = staticField ?? throw new ArgumentNullException(nameof(staticField)); HasDefaultValue = StaticField.HasDefaultValue; HasSimpleValue = StaticField.HasSimpleValue; IsInternal = StaticField.IsInternal; IsObjectReference = StaticField.IsObjectReference; IsPrimitive = StaticField.IsPrimitive; IsPrivate = StaticField.IsPrivate; IsProtected = StaticField.IsProtected; IsPublic = StaticField.IsPublic; IsValueClass = StaticField.IsValueClass; Name = StaticField.Name; Offset = StaticField.Offset; Size = StaticField.Size; Token = StaticField.Token; }
public void StringEmptyIsObtainableTest() { using DataTarget dt = TestTargets.Types.LoadFullDump(); using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime(); ClrHeap heap = runtime.Heap; ClrType stringType = heap.StringType; Assert.NotNull(stringType); ClrStaticField empty = stringType.GetStaticFieldByName("Empty"); Assert.NotNull(empty); string value = empty.ReadString(runtime.AppDomains.Single()); Assert.Equal(string.Empty, value); }
private IEnumerable <ThreadPoolItem> EnumerateLocalThreadPoolItemsInNetFramework(ClrModule mscorlib) { // look into the local stealing queues in each thread TLS // hopefully, they are all stored in static (one per app domain) instance // of ThreadPoolWorkQueue.SparseArray<ThreadPoolWorkQueue.WorkStealingQueue> // var queueType = mscorlib.GetTypeByName("System.Threading.ThreadPoolWorkQueue"); if (queueType == null) { yield break; } ClrStaticField threadQueuesField = queueType.GetStaticFieldByName("allThreadQueues"); if (threadQueuesField == null) { yield break; } foreach (ClrAppDomain domain in _clr.AppDomains) { var threadQueue = threadQueuesField.ReadObject(domain); if (!threadQueue.IsValid) { continue; } var sparseArray = threadQueue.ReadObjectField("m_array").AsArray(); for (int current = 0; current < sparseArray.Length; current++) { var stealingQueue = sparseArray.GetObjectValue(current); if (!stealingQueue.IsValid) { continue; } foreach (var item in EnumerateThreadPoolStealingQueue(stealingQueue)) { yield return(item); } } } }
// The ThreadPool is keeping track of the pending work items into two different areas: // - a global queue: stored by ThreadPoolWorkQueue instances of the ThreadPoolGlobals.workQueue static field // - several per thread (TLS) local queues: stored in SparseArray<ThreadPoolWorkQueue+WorkStealingQueue> linked from ThreadPoolWorkQueue.allThreadQueues static fields // both are using arrays of Task or QueueUserWorkItemCallback // // NOTE: don't show other thread pool related topics such as timer callbacks or wait objects // private IEnumerable <ThreadPoolItem> EnumerateGlobalThreadPoolItemsInNetFramework(ClrModule mscorlib) { ClrType queueType = mscorlib.GetTypeByName("System.Threading.ThreadPoolGlobals"); if (queueType == null) { yield break; } ClrStaticField workQueueField = queueType.GetStaticFieldByName("workQueue"); if (workQueueField == null) { yield break; } // the CLR keeps one static instance per application domain foreach (var appDomain in _clr.AppDomains) { var workQueue = workQueueField.ReadObject(appDomain); if (!workQueue.IsValid) { continue; } // should be System.Threading.ThreadPoolWorkQueue var workQueueType = workQueue.Type; if (workQueueType == null) { continue; } if (string.CompareOrdinal(workQueueType.Name, "System.Threading.ThreadPoolWorkQueue") != 0) { continue; } foreach (var item in EnumerateThreadPoolWorkQueue(workQueue)) { yield return(item); } } }
public void ComponentTypeEventuallyFilledTest() { // https://github.com/microsoft/clrmd/issues/108 // Ensure that a previously created type with a erronous null ComponentType eventually // gets its ComponentType set. using DataTarget dt = TestTargets.Types.LoadFullDump(); using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime(); ClrType fooType = runtime.GetModule(ModuleName).GetTypeByName("Types"); ClrStaticField cq = fooType.GetStaticFieldByName("s_cq"); Assert.NotNull(cq); ClrInstanceField m_head = cq.Type.GetFieldByName("m_head"); ClrInstanceField m_array = m_head.Type.GetFieldByName("m_array"); bool hasSimpleValue = m_array.HasSimpleValue; ClrElementType elementType = m_array.ElementType; ClrType componentType = m_array.Type.ComponentType; // If this assert fails, remove the test. This value is null because currently CLR's // debugging layer doesn't tell us the component type of an array. If we eventually // fix that issue, we would return a non-null m_array.Type.ComponentType, causing // this test to fail but the underlying issue would be fixed. Assert.Null(componentType); ClrObject m_arrayObj = cq.ReadObject().GetObjectField("m_head").GetObjectField("m_array"); // Ensure we are looking at the same ClrType if (dt.CacheOptions.CacheTypes) { Assert.Same(m_array.Type, m_arrayObj.Type); } else { Assert.Equal(m_array.Type, m_arrayObj.Type); } // Assert that we eventually filled in ComponentType after we got a real object for the type Assert.NotNull(m_arrayObj.Type.ComponentType); }
public CacheFieldInfo(ClrStaticField Field, int FieldIndex) { IsStatic = true; IsThreadStatic = false; TypeName = GetFieldTypeName(Field.Type); Name = AdjustFieldName(Field.Name); MethodTable = HeapStatItem.GetMTOfType(Field.Type); Offset = Field.Offset; Token = Field.Type == null ? 0 : Field.Type.MetadataToken; Module = Field.Type == null || Field.Type.Module == null ? 0 : Field.Type.Module.ImageBase; Assembly = Field.Type == null || Field.Type.Module == null ? 0 : Field.Type.Module.AssemblyId; BackField = Field; Size = Field.Size; CorElementType = (int)Field.ElementType; IsArray = Field.Type == null ? false : Field.Type.IsArray; IsValueType = Field.Type == null ? false : Field.Type.IsValueClass || Field.Type.IsPrimitive; IsGeneric = Field.Type == null ? true : Field.Type.Name.Contains('<') && Field.Type.Name.Contains('>') && Field.Type.Name[0] != '<'; Index = FieldIndex; IsEnum = Field.Type == null ? false : Field.Type.IsEnum; IsString = Field.Type == null ? false : Field.Type.IsString; }
public IEnumerable <ObjectInfo> EnumerateManagedWorkItems() { ClrStaticField workQueueField = ClrMdUtils.GetCorlib(runtime).GetTypeByName("System.Threading.ThreadPoolGlobals")?.GetStaticFieldByName("workQueue"); if (workQueueField != null) { object workQueueValue = workQueueField.GetValue(domain); ulong workQueueRef = (workQueueValue == null) ? 0L : (ulong)workQueueValue; if (workQueueRef != 0) { ClrType workQueueType = heap.GetObjectType(workQueueRef); // should be System.Threading.ThreadPoolWorkQueue if (workQueueType?.Name == "System.Threading.ThreadPoolWorkQueue") { foreach (var item in EnumerateThreadPoolWorkQueue(workQueueRef)) { yield return(new ObjectInfo { Address = item, Type = heap.GetObjectType(item) }); } } } } }
public void IntegerObjectClrType() { using (DataTarget dt = TestTargets.Types.LoadFullDump()) { ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime(); ClrHeap heap = runtime.Heap; ClrStaticField field = runtime.GetModule("types.exe").GetTypeByName("Types").GetStaticFieldByName("s_i"); ulong addr = (ulong)field.GetValue(runtime.AppDomains.Single()); ClrType type = heap.GetObjectType(addr); Assert.True(type.IsPrimitive); Assert.False(type.IsObjectReference); Assert.False(type.IsValueClass); object value = type.GetValue(addr); Assert.Equal("42", value.ToString()); Assert.IsType <int>(value); Assert.Equal(42, (int)value); Assert.Contains(addr, heap.EnumerateObjectAddresses()); } }
public void TestStaticFieldModifiers() { using DataTarget dt = TestTargets.NestedTypes.LoadFullDump(); using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime(); ClrModule module = runtime.GetModule(TypeTests.NestedTypesModuleName); ClrType program = module.GetTypeByName("Program"); ClrStaticField publicField = program.GetStaticFieldByName("s_publicField"); Assert.True(publicField.IsPublic); ClrStaticField privateField = program.GetStaticFieldByName("s_privateField"); Assert.True(privateField.IsPrivate); ClrStaticField internalField = program.GetStaticFieldByName("s_internalField"); Assert.True(internalField.IsInternal); ClrStaticField protectedField = program.GetStaticFieldByName("s_protectedField"); Assert.True(protectedField.IsProtected); }
public MDStaticField(ClrStaticField field) { m_field = field; }
public StaticVariableValueWrapper(ClrHeap heap, ClrStaticField field) { m_heap = heap; m_field = field; }
public IEnumerable <TimerInfo> EnumerateTimers() { // the implementation is different between .NET Framework/.NET Core 2.*, and .NET Core 3.0+ // - the former is relying on a single static TimerQueue.s_queue // - the latter uses an array of TimerQueue (static TimerQueue.Instances field) // each queue refers to TimerQueueTimer linked list via its m_timers or _shortTimers/_longTimers fields var timerQueueType = GetMscorlib().GetTypeByName("System.Threading.TimerQueue"); if (timerQueueType == null) { yield break; } // .NET Core case ClrStaticField instancesField = timerQueueType.GetStaticFieldByName("<Instances>k__BackingField"); if (instancesField != null) { // until the ClrMD bug to get static field value is fixed, iterate on each object of the heap // to find each TimerQueue and iterate on (slower but it works) foreach (var obj in _heap.EnumerateObjects()) { var objType = obj.Type; if (objType == null) { continue; } if (objType == _heap.FreeType) { continue; } if (string.Compare(objType.Name, "System.Threading.TimerQueue", StringComparison.Ordinal) != 0) { continue; } // m_timers is the start of the linked list of TimerQueueTimer in pre 3.0 var timersField = objType.GetFieldByName("m_timers"); if (timersField != null) { var currentTimerQueueTimer = obj.ReadObjectField("m_timers"); foreach (var timer in GetTimers(currentTimerQueueTimer, false)) { yield return(timer); } } else { // get short timers timersField = objType.GetFieldByName("_shortTimers"); if (timersField == null) { throw new InvalidOperationException("Missing _shortTimers field. Check the .NET Core version implementation of TimerQueue."); } var currentTimerQueueTimer = obj.ReadObjectField("_shortTimers"); foreach (var timer in GetTimers(currentTimerQueueTimer, true)) { timer.IsShort = true; yield return(timer); } // get long timers currentTimerQueueTimer = obj.ReadObjectField("_longTimers"); foreach (var timer in GetTimers(currentTimerQueueTimer, true)) { timer.IsShort = false; yield return(timer); } } } } else { // .NET Framework implementation var instanceField = timerQueueType.GetStaticFieldByName("s_queue"); if (instanceField == null) { yield break; } foreach (var domain in _clr.AppDomains) { var timerQueue = instanceField.ReadObject(domain); if ((timerQueue.IsNull) || (!timerQueue.IsValid)) { continue; } // m_timers is the start of the list of TimerQueueTimer var currentTimerQueueTimer = timerQueue.ReadObjectField("m_timers"); foreach (var timer in GetTimers(currentTimerQueueTimer, false)) { yield return(timer); } } } }
private IEnumerable <ulong> EnumerateManagedThreadpoolObjects() { _heap = _runtime.GetHeap(); ClrModule mscorlib = GetMscorlib(); if (mscorlib != null) { ClrType queueType = mscorlib.GetTypeByName("System.Threading.ThreadPoolGlobals"); if (queueType != null) { ClrStaticField workQueueField = queueType.GetStaticFieldByName("workQueue"); if (workQueueField != null) { foreach (var appDomain in _runtime.AppDomains) { object workQueueValue = workQueueField.GetValue(appDomain); ulong workQueue = workQueueValue == null ? 0L : (ulong)workQueueValue; ClrType workQueueType = _heap.GetObjectType(workQueue); if (workQueue == 0 || workQueueType == null) { continue; } ulong queueHead; ClrType queueHeadType; do { if (!GetFieldObject(workQueueType, workQueue, "queueHead", out queueHeadType, out queueHead)) { break; } ulong nodes; ClrType nodesType; if (GetFieldObject(queueHeadType, queueHead, "nodes", out nodesType, out nodes) && nodesType.IsArray) { int len = nodesType.GetArrayLength(nodes); for (int i = 0; i < len; ++i) { ulong addr = (ulong)nodesType.GetArrayElementValue(nodes, i); if (addr != 0) { yield return(addr); } } } if (!GetFieldObject(queueHeadType, queueHead, "Next", out queueHeadType, out queueHead)) { break; } } while (queueHead != 0); } } } queueType = mscorlib.GetTypeByName("System.Threading.ThreadPoolWorkQueue"); if (queueType != null) { ClrStaticField threadQueuesField = queueType.GetStaticFieldByName("allThreadQueues"); if (threadQueuesField != null) { foreach (ClrAppDomain domain in _runtime.AppDomains) { ulong?threadQueue = (ulong?)threadQueuesField.GetValue(domain); if (!threadQueue.HasValue || threadQueue.Value == 0) { continue; } ClrType threadQueueType = _heap.GetObjectType(threadQueue.Value); if (threadQueueType == null) { continue; } ulong outerArray = 0; ClrType outerArrayType = null; if (!GetFieldObject(threadQueueType, threadQueue.Value, "m_array", out outerArrayType, out outerArray) || !outerArrayType.IsArray) { continue; } int outerLen = outerArrayType.GetArrayLength(outerArray); for (int i = 0; i < outerLen; ++i) { ulong entry = (ulong)outerArrayType.GetArrayElementValue(outerArray, i); if (entry == 0) { continue; } ClrType entryType = _heap.GetObjectType(entry); if (entryType == null) { continue; } ulong array; ClrType arrayType; if (!GetFieldObject(entryType, entry, "m_array", out arrayType, out array) || !arrayType.IsArray) { continue; } int len = arrayType.GetArrayLength(array); for (int j = 0; j < len; ++j) { ulong addr = (ulong)arrayType.GetArrayElementValue(array, i); if (addr != 0) { yield return(addr); } } } } } } } }
public static ClrObject GetStaticObjectValue(this ClrType mainType, string fieldName) { ClrStaticField field = mainType.GetStaticFieldByName(fieldName); return(field.ReadObject()); }
public IEnumerable <TimerInfo> EnumerateTimers() { // the implementation is different between .NET Framework/.NET Core 2.0 and .NET Core 2.1+ // - the former is relying on a single static TimerQueue.s_queue // - the latter uses an array of TimerQueue (static TimerQueue.Instances field) // each queue refers to TimerQueueTimer linked list via its m_timers field // var timerQueueType = GetMscorlib().GetTypeByName("System.Threading.TimerQueue"); if (timerQueueType == null) { yield break; } // .NET Core 2.1+ case ClrStaticField instancesField = timerQueueType.GetStaticFieldByName("<Instances>k__BackingField"); if (instancesField != null) { // until the ClrMD bug to get static field value is fixed, iterate on each object of the heap // to find each TimerQueue and iterate on (slower but it works) foreach (var obj in _heap.EnumerateObjects()) { var objType = obj.Type; if (objType == null) { continue; } if (objType == _heap.FreeType) { continue; } if (string.Compare(objType.Name, "System.Threading.TimerQueue", StringComparison.Ordinal) != 0) { continue; } // m_timers is the start of the linked list of TimerQueueTimer var currentTimerQueueTimer = obj.ReadObjectField("m_timers"); // iterate on each TimerQueueTimer in the linked list while (currentTimerQueueTimer.Address != 0) { var ti = GetTimerInfo(currentTimerQueueTimer); if (ti == null) { continue; } yield return(ti); currentTimerQueueTimer = currentTimerQueueTimer.ReadObjectField("m_next"); } } } else { // .NET Framework implementation var instanceField = timerQueueType.GetStaticFieldByName("s_queue"); if (instanceField == null) { yield break; } foreach (var domain in _clr.AppDomains) { var timerQueue = instanceField.ReadObject(domain); if ((timerQueue.IsNull) || (!timerQueue.IsValid)) { continue; } // m_timers is the start of the list of TimerQueueTimer var currentTimerQueueTimer = timerQueue.ReadObjectField("m_timers"); while (currentTimerQueueTimer.IsValid) { var ti = GetTimerInfo(currentTimerQueueTimer); if (ti == null) { continue; } yield return(ti); currentTimerQueueTimer = currentTimerQueueTimer.ReadObjectField("m_next"); } } } }
public void RunDone() { _workItems = new Dictionary <string, WorkInfo>(); _workItemCount = 0; _tasks = new Dictionary <string, WorkInfo>(); _taskCount = 0; ClrMDHelper helper = new ClrMDHelper(_host.Session.Clr); // The ThreadPool is keeping track of the pending work items into two different areas: // - a global queue: stored by ThreadPoolWorkQueue instances of the ThreadPoolGlobals.workQueue static field // - several per thread (TLS) local queues: stored in SparseArray<ThreadPoolWorkQueue+WorkStealingQueue> linked from ThreadPoolWorkQueue.allThreadQueues static fields // both are using arrays of Task or QueueUserWorkItemCallback // // NOTE: don't show other thread pool related topics such as timer callbacks or wait objects // try { var heap = _host.Session.Clr.Heap; var clr = _host.Session.Clr; _host.WriteLine("global work item queue________________________________"); // look for the ThreadPoolGlobals.workQueue static field ClrModule mscorlib = helper.GetMscorlib(); if (mscorlib == null) { return; } ClrType queueType = mscorlib.GetTypeByName("System.Threading.ThreadPoolGlobals"); if (queueType == null) { return; } ClrStaticField workQueueField = queueType.GetStaticFieldByName("workQueue"); if (workQueueField == null) { return; } // the CLR keeps one static instance per application domain foreach (var appDomain in clr.AppDomains) { object workQueueValue = workQueueField.GetValue(appDomain); ulong workQueueRef = (workQueueValue == null) ? 0L : (ulong)workQueueValue; if (workQueueRef == 0) { continue; } // should be System.Threading.ThreadPoolWorkQueue ClrType workQueueType = heap.GetObjectType(workQueueRef); if (workQueueType == null) { continue; } if (workQueueType.Name != "System.Threading.ThreadPoolWorkQueue") { continue; } if (!DumpThreadPoolWorkQueue(workQueueType, workQueueRef)) { _host.WriteLine("Impossible to dump thread pool work queue @ 0x" + workQueueRef.ToString("X")); } } // look into the local stealing queues in each thread TLS // hopefully, they are all stored in static (one per app domain) instance // of ThreadPoolWorkQueue.SparseArray<ThreadPoolWorkQueue.WorkStealingQueue> // _host.WriteLine("\r\nlocal per thread work items_____________________________________"); try { queueType = mscorlib.GetTypeByName("System.Threading.ThreadPoolWorkQueue"); if (queueType == null) { return; } ClrStaticField threadQueuesField = queueType.GetStaticFieldByName("allThreadQueues"); if (threadQueuesField == null) { return; } foreach (ClrAppDomain domain in clr.AppDomains) { ulong?threadQueue = (ulong?)threadQueuesField.GetValue(domain); if (!threadQueue.HasValue || threadQueue.Value == 0) { continue; } ClrType threadQueueType = heap.GetObjectType(threadQueue.Value); if (threadQueueType == null) { continue; } var sparseArrayRef = _host.Session.GetFieldValue(threadQueue.Value, "m_array"); _host.Session.ForEach((ulong)sparseArrayRef, stealingQueue => { if (stealingQueue != 0) { var arrayRef = _host.Session.GetFieldValue(stealingQueue, "m_array"); DumpThreadPoolWorkItems((ulong)arrayRef); } }); } } finally { // provide a summary sorted by count // tasks first if any if (_tasks.Values.Count > 0) { foreach (var item in _tasks.Values.OrderBy(wi => wi.Count)) { _host.WriteLine(string.Format(" {0,4} Task {1}", item.Count.ToString(), item.Name)); } _host.WriteLine(" ----"); _host.WriteLine(string.Format(" {0,4}\r\n", _taskCount.ToString())); } // then QueueUserWorkItem next if any if (_workItems.Values.Count > 0) { foreach (var item in _workItems.Values.OrderBy(wi => wi.Count)) { _host.WriteLine(string.Format(" {0,4} Work {1}", item.Count.ToString(), item.Name)); } _host.WriteLine(" ----"); _host.WriteLine(string.Format(" {0,4}\r\n", _workItemCount.ToString())); } var threadPool = _host.Session.Clr.ThreadPool; _host.WriteLine(string.Format( "\r\nCPU = {0}% for {1} threads (#idle = {2} + #running = {3} | #dead = {4} | #max = {5})", threadPool.CpuUtilization.ToString(), threadPool.TotalThreads.ToString(), threadPool.IdleThreads.ToString(), threadPool.RunningThreads.ToString(), _host.Session.Clr.Threads.Count(t => t.IsThreadpoolWorker && !t.IsThreadpoolCompletionPort && !t.IsAlive && !t.IsThreadpoolGate && !t.IsThreadpoolTimer && !t.IsThreadpoolWait).ToString(), threadPool.MaxThreads.ToString() )); // show the running worker threads DumpRunningThreadpoolThreads(helper); } } catch (Exception x) { _host.WriteLine(x.Message); } }
private static IEnumerable <TimerInfo> EnumerateTimers(ClrRuntime clr) { var timerQueueType = Utils.GetMscorlib(clr).GetTypeByName("System.Threading.TimerQueue"); if (timerQueueType == null) { yield break; } ClrStaticField instanceField = timerQueueType.GetStaticFieldByName("s_queue"); if (instanceField == null) { yield break; } var heap = clr.Heap; foreach (ClrAppDomain domain in clr.AppDomains) { ulong?timerQueue = (ulong?)instanceField.GetValue(domain); if (!timerQueue.HasValue || timerQueue.Value == 0) { continue; } ClrType t = heap.GetObjectType(timerQueue.Value); if (t == null) { continue; } // m_timers is the start of the list of TimerQueueTimer var currentPointer = Utils.GetFieldValue(heap, timerQueue.Value, "m_timers"); while ((currentPointer != null) && (((ulong)currentPointer) != 0)) { // currentPointer points to a TimerQueueTimer instance ulong currentTimerQueueTimerRef = (ulong)currentPointer; TimerInfo ti = new TimerInfo() { TimerQueueTimerAddress = currentTimerQueueTimerRef }; var val = Utils.GetFieldValue(heap, currentTimerQueueTimerRef, "m_dueTime"); ti.DueTime = (uint)val; val = Utils.GetFieldValue(heap, currentTimerQueueTimerRef, "m_period"); ti.Period = (uint)val; val = Utils.GetFieldValue(heap, currentTimerQueueTimerRef, "m_canceled"); ti.Cancelled = (bool)val; val = Utils.GetFieldValue(heap, currentTimerQueueTimerRef, "m_state"); ti.StateTypeName = ""; if (val == null) { ti.StateAddress = 0; } else { ti.StateAddress = (ulong)val; var stateType = heap.GetObjectType(ti.StateAddress); if (stateType != null) { ti.StateTypeName = stateType.Name; } } // decypher the callback details val = Utils.GetFieldValue(heap, currentTimerQueueTimerRef, "m_timerCallback"); if (val != null) { ulong elementAddress = (ulong)val; if (elementAddress == 0) { continue; } var elementType = heap.GetObjectType(elementAddress); if (elementType != null) { if (elementType.Name == "System.Threading.TimerCallback") { ti.MethodName = Utils.BuildTimerCallbackMethodName(clr, heap, elementAddress); } else { ti.MethodName = "<" + elementType.Name + ">"; } } else { ti.MethodName = "{no callback type?}"; } } else { ti.MethodName = "???"; } yield return(ti); currentPointer = Utils.GetFieldValue(heap, currentTimerQueueTimerRef, "m_next"); } } }