public void Execute(CommandExecutionContext context) { if (!CommandHelpers.VerifyValidObjectAddress(context, ObjectAddress)) return; var type = context.Heap.GetObjectType(ObjectAddress); if (!type.IsArray) { context.WriteError("The object at the specified address is not an array."); return; } var size = type.GetSize(ObjectAddress); var length = type.GetArrayLength(ObjectAddress); context.WriteLine("Name: {0}", type.Name); context.WriteLine("Size: {0}(0x{1:x}) bytes", size, size); context.WriteLine("Array: Number of elements {0}, Type {1} {2}", length, type.ComponentType.Name, type.ComponentType.IsValueClass ? "(value type)" : "(reference type)"); for (int i = 0; i < length; ++i) { context.Write("[{0}] ", i); object value; if (type.ComponentType.IsValueClass) { value = type.GetArrayElementAddress(ObjectAddress, i); if (value != null) { context.WriteLink( String.Format("{0:x16}", value), String.Format("!do {0:x16} --type {1}", value, type.ComponentType.Name) ); } else { context.Write("<null>"); } } else { value = type.GetArrayElementValue(ObjectAddress, i); ulong elementAddr = type.GetArrayElementAddress(ObjectAddress, i); ulong elementRef; if (context.Runtime.ReadPointer(elementAddr, out elementRef)) { context.WriteLink( String.Format("{0:x16}", value ?? "<null>"), String.Format("!do {0:x16}", elementRef) ); } else { context.Write("{0:x16}", value ?? "<null>"); } } context.WriteLine(); } }
private void DisplayFieldRecursively <TField>(TField field, IFieldValueForDisplayRetriever <TField> retriever, int offset, string baseName = "", int depth = 0) where TField : ClrField { bool inner = depth > 0; var address = retriever.GetFieldAddress(field, inner); _context.Write(retriever.GetDisplayString(field, offset, baseName, inner)); if (field.IsObjectReferenceNotString()) { _context.WriteLink("", String.Format("!do {0}", retriever.GetFieldValue(field, inner))); } if (NoRecurse && field.ElementType == ClrElementType.Struct) { _context.WriteLink("", String.Format("!do {0:x16} --type {1}", address, field.Type.Name)); } _context.WriteLine(); if (!NoRecurse && field.ElementType == ClrElementType.Struct) { foreach (var innerField in field.Type.Fields) { var innerRetriever = new InstanceFieldValueForDisplayRetriever(address); DisplayFieldRecursively(innerField, innerRetriever, offset + innerField.Offset, baseName + field.Name + ".", depth + 1); } } }
private void ProcessStacks(IEnumerable <ThreadAndStack> stacks, int depth = 0) { if (depth >= Depth) { return; } var grouping = from stack in stacks where stack.Stack.Any() group stack by stack.Stack.First() into g orderby g.Count() descending select g; if (grouping.Count() == 1) { var stackGroup = grouping.First(); _context.WriteLine("{0}| {1}", new String(' ', depth * 2), stackGroup.Key); ProcessStacks(TrimOne(stackGroup), depth); } else { foreach (var stackGroup in grouping) { _context.Write("{0}+ {1} ", new String(' ', depth * 2), stackGroup.Key); if (!NoThreadDetails) { foreach (var ts in stackGroup) { if (ts.ManagedThreadId != 0) { _context.WriteLink( String.Format("M{0}", ts.ManagedThreadId), String.Format("~ {0}; !clrstack", ts.ManagedThreadId) ); } else { _context.WriteLink( String.Format("OS{0}", ts.OSThreadId), String.Format("!mk {0}", ts.OSThreadId) ); } _context.Write(" "); } } _context.WriteLine(); ProcessStacks(TrimOne(stackGroup), depth + 1); } } }
public void Execute(CommandExecutionContext context) { if (!CommandHelpers.VerifyHasHeapIndex(context)) return; if (!CommandHelpers.VerifyValidObjectAddress(context, ObjectAddress)) return; int pathsDisplayed = 0; foreach (var path in context.HeapIndex.FindPaths(ObjectAddress, MaxResults, MaxLocalRoots, MaxDepth, RunInParallel)) { context.WriteLine("{0:x16} -> {1:x16} {2}", path.Root.Address, path.Root.Object, path.Root.DisplayText); foreach (var obj in path.Chain) { string objHex = String.Format("{0:x16}", obj); context.Write(" -> "); context.WriteLink(objHex, "!do " + objHex); context.WriteLine(" {0}", context.Heap.GetObjectType(obj).Name); } context.WriteLine(); ++pathsDisplayed; } context.WriteLine("Total paths displayed: {0}", pathsDisplayed); if (pathsDisplayed == 0) { context.WriteLine("Number of paths may be affected by maximum depth setting. " + "If you are not seeing enough results, consider increasing --maxDepth."); } }
private void ManagedHeapFragmentation() { var freeSpaceBySegment = new Dictionary <ClrSegment, ulong>(); ulong totalFreeSize = 0; foreach (ClrSegment segment in _context.Heap.Segments) { for (ulong currentObject = segment.FirstObject; currentObject != 0; currentObject = segment.NextObject(currentObject)) { ClrType type = _context.Heap.GetObjectType(currentObject); if (type != null && type.IsFree) { ulong size = type.GetSize(currentObject); if (!freeSpaceBySegment.ContainsKey(segment)) { freeSpaceBySegment.Add(segment, size); } else { freeSpaceBySegment[segment] += size; } totalFreeSize += size; } } } _context.WriteLine("Fragmentation statistics:"); _context.WriteLine( "{0,-4} {1,-20} {2,-12} {3,-12} {4,-12} {5,-12} {6,-10} {7,-10}", "#", "Base", "Size", "Committed", "Reserved", "Fragmented", "% Frag", "Type"); for (int segmentIdx = 0; segmentIdx < _context.Heap.Segments.Count; ++segmentIdx) { var segment = _context.Heap.Segments[segmentIdx]; var fragmented = freeSpaceBySegment.ContainsKey(segment) ? freeSpaceBySegment[segment] : 0; _context.Write( "{0,-4} {1,-20:x16} {2,-12} {3,-12} {4,-12} {5,-12} {6,-10:0.00%} {7,-5} ", segmentIdx, segment.Start, segment.Length.ToMemoryUnits(), (segment.CommittedEnd - segment.Start).ToMemoryUnits(), (segment.ReservedEnd - segment.Start).ToMemoryUnits(), fragmented.ToMemoryUnits(), fragmented / (double)segment.Length, segment.IsLarge ? "LOH" : "SOH"); _context.WriteLink( "", String.Format("!hq tabular from o in ObjectsInSegment({0}) " + "group (long)o.__Size by o.__Type into g " + "let totalSize = g.Sum() " + "orderby totalSize ascending " + "select new {{ Type = g.Key, TotalSize = totalSize }}", segmentIdx) ); _context.WriteLine(); } _context.WriteLine(); _context.WriteLine("Total size of free objects: {0}", totalFreeSize.ToMemoryUnits()); _context.WriteLine(); }
public void Execute(CommandExecutionContext context) { if (!CommandHelpers.VerifyHasHeapIndex(context)) { return; } if (!CommandHelpers.VerifyValidObjectAddress(context, ObjectAddress)) { return; } int pathsDisplayed = 0; foreach (var path in context.HeapIndex.FindPaths(ObjectAddress, MaxResults, MaxLocalRoots, MaxDepth, RunInParallel)) { context.WriteLine("{0:x16} -> {1:x16} {2}", path.Root.Address, path.Root.Object, path.Root.DisplayText); foreach (var obj in path.Chain) { string objHex = String.Format("{0:x16}", obj); context.Write(" -> "); context.WriteLink(objHex, "!do " + objHex); context.WriteLine(" {0}", context.Heap.GetObjectType(obj).Name); } context.WriteLine(); ++pathsDisplayed; } context.WriteLine("Total paths displayed: {0}", pathsDisplayed); if (pathsDisplayed == 0) { context.WriteLine("Number of paths may be affected by maximum depth setting. " + "If you are not seeing enough results, consider increasing --maxDepth."); } }
private static void DisplayOneArgumentOrLocal(CommandExecutionContext context, string which, ArgumentOrLocal argOrLocal) { context.Write(" {0} {1,-10} = {2} ({3},{4} {5} bytes) ", which, argOrLocal.Name, argOrLocal.ValueRaw(), argOrLocal.DynamicTypeName, argOrLocal.StaticAndDynamicTypesAreTheSame ? "" : (" original " + argOrLocal.StaticTypeName + ","), argOrLocal.Size); if (argOrLocal.ObjectAddress != 0) { context.WriteLink("", String.Format("!do {0:x16}", argOrLocal.ObjectAddress)); } else if (argOrLocal.HasNonTrivialValueToDisplay) { context.WriteLink("", String.Format("!do {0:x16} --type {1}", argOrLocal.Location, argOrLocal.ClrType.Name)); } context.WriteLine(); }
private void DisplayChainForThreadAux(ClrThread thread, int depth, HashSet <int> visitedThreadIds) { _context.WriteLink( String.Format("{0}+ Thread {1}", new string(' ', depth * 2), thread.ManagedThreadId), String.Format("~ {0}; !clrstack", thread.ManagedThreadId)); _context.WriteLine(); if (visitedThreadIds.Contains(thread.ManagedThreadId)) { _context.WriteLine("{0}*** DEADLOCK!", new string(' ', depth * 2)); return; } visitedThreadIds.Add(thread.ManagedThreadId); foreach (var blockingObject in thread.BlockingObjects) { _context.Write("{0}| {1} ", new string(' ', (depth + 1) * 2), blockingObject.Reason); var type = _context.Heap.GetObjectType(blockingObject.Object); if (type != null && !String.IsNullOrEmpty(type.Name)) { _context.WriteLink( String.Format("{0:x16} {1}", blockingObject.Object, type.Name), String.Format("!do {0:x16}", blockingObject.Object)); } else { _context.Write("{0:x16}", blockingObject.Object); } _context.WriteLine(); foreach (var owner in blockingObject.Owners) { if (owner == null) // ClrMD sometimes reports this nonsense { continue; } DisplayChainForThreadAux(owner, depth + 2, visitedThreadIds); } } }
public void Execute(CommandExecutionContext context) { context.WriteLine("{0,-20} {1,-10} {2,-8} {3,-20} {4,-20}", "Address", "Type", "Locked", "Owner(s)", "Waiter(s)"); foreach (var blockingObject in context.Runtime.GetHeap().EnumerateBlockingObjects()) { context.Write("{0,-20:x16} {1,-10} {2,-8} {3,-20} {4,-20}", blockingObject.Object, blockingObject.Reason, blockingObject.Taken ? 1 : 0, String.Join(", ", from thread in blockingObject.Owners where thread != null select thread.ManagedThreadId), String.Join(", ", from thread in blockingObject.Waiters where thread != null select thread.ManagedThreadId)); context.WriteLink("", String.Format("!do {0:x16}", blockingObject.Object)); context.WriteLine(); } }
private void DisplayChainForThread(UnifiedThread unifiedThread, int depth, HashSet <uint> visitedThreadIds) { if (unifiedThread.IsManagedThread) { var command = String.Format("~ {0}; !mk", unifiedThread.ManagedThreadId); _context.WriteLink(String.Format("{0}+ OS Thread {1}", new string(' ', depth * 2), unifiedThread.OSThreadId), command); } else { _context.Write("+ OS Thread {0}", unifiedThread.OSThreadId); } _context.WriteLine(); if (visitedThreadIds.Contains(unifiedThread.OSThreadId)) { _context.WriteLine("{0}*** DEADLOCK!", new string(' ', depth * 2)); return; } visitedThreadIds.Add(unifiedThread.OSThreadId); DisplayThreadBlockingObjects(unifiedThread, depth, unifiedThread.BlockingObjects, visitedThreadIds); }
public void Execute(CommandExecutionContext context) { if (!CommandHelpers.VerifyHasHeapIndex(context)) { return; } if (!CommandHelpers.VerifyValidObjectAddress(context, ObjectAddress)) { return; } var type = context.Heap.GetObjectType(ObjectAddress); context.WriteLine("Note: unrooted (dead) objects will not have any referencing objects displayed."); context.WriteLine("Object {0:x16} ({1}) is referenced by the following objects:", ObjectAddress, type.Name); foreach (var referencingObj in context.HeapIndex.FindRefs(ObjectAddress)) { string refHex = String.Format("{0:x16}", referencingObj); context.WriteLink(refHex, "!do " + refHex); context.WriteLine(" ({0})", context.Heap.GetObjectType(referencingObj).Name); } context.WriteLine("Object {0:x16} ({1}) references the following objects:", ObjectAddress, type.Name); type.EnumerateRefsOfObject(ObjectAddress, (child, _) => { var childType = context.Heap.GetObjectType(child); if (childType == null || String.IsNullOrEmpty(childType.Name)) { return; } string refHex = String.Format("{0:x16}", child); context.WriteLink(refHex, "!do " + refHex); context.WriteLine(" ({0})", childType.Name); }); }
public void Execute(CommandExecutionContext context) { context.WriteLine("{0,-20} {1,-20} {2}", "Address", "Object", "Type"); foreach (var localRoot in context.CurrentThread.EnumerateStackObjects()) { var type = context.Heap.GetObjectType(localRoot.Object); context.Write("{0,-20:x16} {1,-20:x16} {2} ", localRoot.Address, localRoot.Object, type == null ? "" : type.Name); if (type != null && !type.IsFree) { context.WriteLink("", String.Format("!do {0:x16}", localRoot.Object)); } context.WriteLine(); } }
public void Execute(CommandExecutionContext context) { _searchRegex = new Regex(SearchString); foreach (var thread in context.Runtime.Threads) { if (ThreadMatchesFilter(thread)) { context.WriteLink( String.Format("Thread {0}", thread.ManagedThreadId), String.Format("~ {0}", thread.ManagedThreadId) ); context.WriteLine(); thread.WriteCurrentStackTraceToContext(context, displayArgumentsAndLocals: false); } } }
private void ManagedHeapFragmentation() { var freeSpaceBySegment = _context.Heap.GetFreeSpaceBySegment(); ulong totalFreeSize = (ulong)freeSpaceBySegment.Values.Sum(f => (long)f); _context.WriteLine("Fragmentation statistics:"); _context.WriteLine( "{0,-4} {1,-20} {2,-12} {3,-12} {4,-12} {5,-12} {6,-10} {7,-10}", "#", "Base", "Size", "Committed", "Reserved", "Fragmented", "% Frag", "Type"); for (int segmentIdx = 0; segmentIdx < _context.Heap.Segments.Count; ++segmentIdx) { var segment = _context.Heap.Segments[segmentIdx]; var fragmented = freeSpaceBySegment.ContainsKey(segment) ? freeSpaceBySegment[segment] : 0; _context.Write( "{0,-4} {1,-20:x16} {2,-12} {3,-12} {4,-12} {5,-12} {6,-10:0.00%} {7,-5} ", segmentIdx, segment.Start, segment.Length.ToMemoryUnits(), (segment.CommittedEnd - segment.Start).ToMemoryUnits(), (segment.ReservedEnd - segment.Start).ToMemoryUnits(), fragmented.ToMemoryUnits(), fragmented / (double)segment.Length, segment.IsLarge ? "LOH" : "SOH"); _context.WriteLink( "", String.Format("!hq tabular from o in ObjectsInSegment({0}) " + "group (long)o.__Size by o.__Type into g " + "let totalSize = g.Sum() " + "orderby totalSize ascending " + "select new {{ Type = g.Key, TotalSize = totalSize }}", segmentIdx) ); _context.WriteLine(); } _context.WriteLine(); _context.WriteLine("Total size of free objects: {0}", totalFreeSize.ToMemoryUnits()); _context.WriteLine(); }
public void Execute(CommandExecutionContext context) { _context = context; ClrType type; if (!String.IsNullOrEmpty(TypeName)) { type = context.Heap.GetTypeByName(TypeName); if (type == null) { context.WriteError("There is no type named '{0}'.", TypeName); return; } } else { type = context.Heap.GetObjectType(ObjectAddress); if (type == null || String.IsNullOrEmpty(type.Name)) { context.WriteError("The specified address is not an object."); return; } } ulong mt = 0; if (type.IsObjectReference && !context.Runtime.ReadPointer(ObjectAddress, out mt)) { context.WriteWarning("Unable to retrieve MT for object."); } var size = type.GetSize(ObjectAddress); context.Write("Name: {0}", type.Name); var dynamicObj = context.Heap.GetDynamicObject(ObjectAddress); if (type.IsArray || dynamicObj.IsList() || dynamicObj.IsDictionary()) { context.WriteLink(" <display elements>", String.Format("!dumpcollection {0:x16}", ObjectAddress)); } context.WriteLine(); if (mt != 0) { context.WriteLine("MT: {0:x16}", mt); } context.WriteLine("Size: {0}(0x{1:x}) bytes", size, size); if (type.IsArray) { context.WriteLine("Array: size {0}, element type {1}", type.GetArrayLength(ObjectAddress), type.ArrayComponentType != null ? type.ArrayComponentType.Name : "<unknown>"); } context.WriteLine("Assembly: {0}", type.Module.FileName); if (type.HasSimpleValue) { context.WriteLine("Value: {0}", type.GetValue(ObjectAddress)); } if (!NoFields && type.Fields.Count > 0) { context.WriteLine("Fields:"); context.WriteLine("{0,-8} {1,-20} {2,-3} {3,-10} {4,-20} {5}", "Offset", "Type", "VT", "Attr", "Value", "Name"); foreach (var field in type.Fields) { DisplayFieldRecursively(field, new InstanceFieldValueForDisplayRetriever(ObjectAddress), field.Offset, depth: type.IsValueClass ? 1 : 0); } foreach (var field in type.ThreadStaticFields) { context.WriteLine("{0,-8:x} {1,-20} {2,-3} {3,-10} {4,-20:x16} {5}", field.Offset, field.GetFieldTypeNameTrimmed(), (field.IsPrimitive() || field.IsValueClass()) ? 1 : 0, "shared", "thrstatic", field.Name); foreach (var appDomain in context.Runtime.AppDomains) { foreach (var thread in context.Runtime.Threads) { DisplayFieldRecursively(field, new ThreadStaticFieldValueForDisplayRetriever(appDomain, thread), field.Offset); } } } foreach (var field in type.StaticFields) { context.WriteLine("{0,-8:x} {1,-20} {2,-3} {3,-10} {4,-20:x16} {5}", field.Offset, field.GetFieldTypeNameTrimmed(), (field.IsPrimitive() || field.IsValueClass()) ? 1 : 0, "shared", "static", field.Name); foreach (var appDomain in context.Runtime.AppDomains) { DisplayFieldRecursively(field, new StaticFieldValueForDisplayRetriever(appDomain), field.Offset); } } } }
public void Execute(CommandExecutionContext context) { context.WriteLine("{0} CLR threads, {1} CLR thread pool threads, {2} background threads", context.Runtime.Threads.Count, context.Runtime.Threads.Count(t => t.IsThreadPoolThread()), context.Runtime.Threads.Count(t => t.IsBackground)); context.WriteLine("{0,-6} {1,-6} {2,-6} {3,-6} {4,-20} {5,-30}", "MgdId", "OSId", "Lock#", "Apt", "Special", "Exception"); foreach (var thread in context.Runtime.Threads) { context.Write("{0,-6} {1,-6} {2,-6} {3,-6} {4,-20} {5,-30} ", thread.ManagedThreadId, thread.OSThreadId, thread.LockCount, thread.ApartmentDescription(), thread.SpecialDescription(), (thread.CurrentException != null ? thread.CurrentException.Type.Name : "").TrimStartToLength(30)); context.WriteLink("", String.Format("~ {0}; {1}", thread.ManagedThreadId, thread.CurrentException != null ? "!pe" : "!clrstack")); context.WriteLine(); } if (!DisplayNativeThreads) { return; } context.WriteLine(); context.WriteLine("{0,-6} {1,-6} {2,-10} {3}", "OSId", "MgdId", "ExitCode", "StartAddress"); using (var target = context.CreateTemporaryDbgEngTarget()) { var osThreadIds = target.GetOSThreadIds(); var symbols = (IDebugSymbols)target.DebuggerInterface; var advanced = (IDebugAdvanced2)target.DebuggerInterface; int size; byte[] buffer = new byte[Marshal.SizeOf(typeof(DEBUG_THREAD_BASIC_INFORMATION))]; GCHandle gch = GCHandle.Alloc(buffer, GCHandleType.Pinned); try { for (uint engineThreadId = 0; engineThreadId < osThreadIds.Length; ++engineThreadId) { if (0 != advanced.GetSystemObjectInformation(DEBUG_SYSOBJINFO.THREAD_BASIC_INFORMATION, 0, engineThreadId, buffer, buffer.Length, out size)) { continue; } var info = (DEBUG_THREAD_BASIC_INFORMATION)Marshal.PtrToStructure( gch.AddrOfPinnedObject(), typeof(DEBUG_THREAD_BASIC_INFORMATION)); var managedThread = context.Runtime.Threads.SingleOrDefault(t => t.OSThreadId == osThreadIds[engineThreadId]); context.Write("{0,-6} {1,-6} {2,-10} {3:x16} ", osThreadIds[engineThreadId], managedThread != null ? managedThread.ManagedThreadId.ToString() : "", info.ExitStatus == 259 ? "active" : info.ExitStatus.ToString(), info.StartOffset); uint symSize; ulong displacement; StringBuilder symbolName = new StringBuilder(2048); if (0 == symbols.GetNameByOffset(info.StartOffset, symbolName, symbolName.Capacity, out symSize, out displacement)) { context.Write("{0} ", symbolName.ToString()); } context.WriteLink("", String.Format("!mk {0}", osThreadIds[engineThreadId])); context.WriteLine(); } } finally { gch.Free(); } } }
public void Execute(CommandExecutionContext context) { var heap = context.Runtime.GetHeap(); var readyForFinalization = context.Runtime.EnumerateFinalizerQueueObjectAddresses().ToList(); ulong totalCount = 0; if (StatisticsOnly) { context.WriteLine("{0,-10} {1,-10} {2}", "Count", "Size", "Class Name"); var query = from obj in readyForFinalization let type = heap.GetObjectType(obj) where type != null && !String.IsNullOrEmpty(type.Name) let size = (long)type.GetSize(obj) group size by type.Name into g let totalSize = g.Sum() let count = g.Count() orderby totalSize descending select new { Count = count, Size = totalSize, ClassName = g.Key }; foreach (var row in query) { context.WriteLine("{0,-10} {1,-10} {2}", row.Count, row.Size, row.ClassName); totalCount += (ulong)row.Count; } } else { context.WriteLine("{0,-20} {1,-10} {2}", "Address", "Size", "Class Name"); foreach (var objPtr in readyForFinalization) { var type = heap.GetObjectType(objPtr); if (type == null || String.IsNullOrEmpty(type.Name)) return; context.WriteLink( String.Format("{0,-20:x16} {1,-10} {2}", objPtr, type.GetSize(objPtr), type.Name), String.Format("!do {0:x16}", objPtr) ); context.WriteLine(); ++totalCount; } } context.WriteLine("# of objects ready for finalization: {0}", totalCount); context.WriteLine("Memory reachable from these objects: {0}", heap.SizeReachableFromObjectSet(readyForFinalization).ToMemoryUnits()); var finalizerThread = context.Runtime.Threads.SingleOrDefault(t => t.IsFinalizer); if (finalizerThread != null && finalizerThread.BlockingObjects.Count > 0) { context.WriteLine(); context.WriteLine("The finalizer thread is blocked! Blocking objects:"); foreach (var blockingObject in finalizerThread.BlockingObjects) { context.Write("\t{0} ", blockingObject.Reason); string objHex = String.Format("{0:x16}", blockingObject.Object); context.WriteLink(objHex, "!do " + objHex); context.WriteLine(); } context.WriteLine("Blocked at:"); foreach (var frame in finalizerThread.StackTrace.Take(3)) { context.WriteLine("\t" + frame.DisplayString); } context.WriteLink( "\t... view full stack", String.Format("~ {0}; !clrstack", finalizerThread.ManagedThreadId)); context.WriteLine(); } }
public void Execute(CommandExecutionContext context) { if (!CommandHelpers.VerifyValidObjectAddress(context, ObjectAddress)) { return; } var type = context.Heap.GetObjectType(ObjectAddress); if (!type.IsArray) { context.WriteError("The object at the specified address is not an array."); return; } var size = type.GetSize(ObjectAddress); var length = type.GetArrayLength(ObjectAddress); context.WriteLine("Name: {0}", type.Name); context.WriteLine("Size: {0}(0x{1:x}) bytes", size, size); context.WriteLine("Array: Number of elements {0}, Type {1} {2}", length, type.ArrayComponentType.Name, type.ArrayComponentType.IsValueClass ? "(value type)" : "(reference type)"); for (int i = 0; i < length; ++i) { context.Write("[{0}] ", i); object value; if (type.ArrayComponentType.IsValueClass) { value = type.GetArrayElementAddress(ObjectAddress, i); if (value != null) { context.WriteLink( String.Format("{0:x16}", value), String.Format("!do {0:x16} --type {1}", value, type.ArrayComponentType.Name) ); } else { context.Write("<null>"); } } else { value = type.GetArrayElementValue(ObjectAddress, i); ulong elementAddr = type.GetArrayElementAddress(ObjectAddress, i); ulong elementRef; if (context.Runtime.ReadPointer(elementAddr, out elementRef)) { context.WriteLink( String.Format("{0:x16}", value ?? "<null>"), String.Format("!do {0:x16}", elementRef) ); } else { context.Write("{0:x16}", value ?? "<null>"); } } context.WriteLine(); } }
public void Execute(CommandExecutionContext context) { context.WriteLine("{0} CLR threads, {1} CLR thread pool threads, {2} background threads", context.Runtime.Threads.Count, context.Runtime.Threads.Count(t => t.IsThreadPoolThread()), context.Runtime.Threads.Count(t => t.IsBackground)); context.WriteLine("{0,-6} {1,-6} {2,-6} {3,-6} {4,-20} {5,-30}", "MgdId", "OSId", "Lock#", "Apt", "Special", "Exception"); foreach (var thread in context.Runtime.Threads) { context.Write("{0,-6} {1,-6} {2,-6} {3,-6} {4,-20} {5,-30} ", thread.ManagedThreadId, thread.OSThreadId, thread.LockCount, thread.ApartmentDescription(), thread.SpecialDescription(), (thread.CurrentException != null ? thread.CurrentException.Type.Name : "").TrimStartToLength(30)); context.WriteLink("", String.Format("~ {0}; {1}", thread.ManagedThreadId, thread.CurrentException != null ? "!pe" : "!clrstack")); context.WriteLine(); } if (!DisplayNativeThreads) return; context.WriteLine(); context.WriteLine("{0,-6} {1,-6} {2,-10} {3}", "OSId", "MgdId", "ExitCode", "StartAddress"); using (var target = context.CreateTemporaryDbgEngTarget()) { var osThreadIds = target.GetOSThreadIds(); var symbols = (IDebugSymbols)target.DebuggerInterface; var advanced = (IDebugAdvanced2)target.DebuggerInterface; int size; byte[] buffer = new byte[Marshal.SizeOf(typeof(DEBUG_THREAD_BASIC_INFORMATION))]; GCHandle gch = GCHandle.Alloc(buffer, GCHandleType.Pinned); try { for (uint engineThreadId = 0; engineThreadId < osThreadIds.Length; ++engineThreadId) { if (0 != advanced.GetSystemObjectInformation(DEBUG_SYSOBJINFO.THREAD_BASIC_INFORMATION, 0, engineThreadId, buffer, buffer.Length, out size)) continue; var info = (DEBUG_THREAD_BASIC_INFORMATION)Marshal.PtrToStructure( gch.AddrOfPinnedObject(), typeof(DEBUG_THREAD_BASIC_INFORMATION)); var managedThread = context.Runtime.Threads.SingleOrDefault(t => t.OSThreadId == osThreadIds[engineThreadId]); context.Write("{0,-6} {1,-6} {2,-10} {3:x16} ", osThreadIds[engineThreadId], managedThread != null ? managedThread.ManagedThreadId.ToString() : "", info.ExitStatus == 259 ? "active" : info.ExitStatus.ToString(), info.StartOffset); uint symSize; ulong displacement; StringBuilder symbolName = new StringBuilder(2048); if (0 == symbols.GetNameByOffset(info.StartOffset, symbolName, symbolName.Capacity, out symSize, out displacement)) { context.Write("{0} ", symbolName.ToString()); } context.WriteLink("", String.Format("!mk {0}", osThreadIds[engineThreadId])); context.WriteLine(); } } finally { gch.Free(); } } }
public void Execute(CommandExecutionContext context) { var heap = context.Runtime.GetHeap(); var readyForFinalization = context.Runtime.EnumerateFinalizerQueue().ToList(); ulong totalCount = 0; if (StatisticsOnly) { context.WriteLine("{0,-10} {1,-10} {2}", "Count", "Size", "Class Name"); var query = from obj in readyForFinalization let type = heap.GetObjectType(obj) where type != null && !String.IsNullOrEmpty(type.Name) let size = (long)type.GetSize(obj) group size by type.Name into g let totalSize = g.Sum() let count = g.Count() orderby totalSize descending select new { Count = count, Size = totalSize, ClassName = g.Key }; foreach (var row in query) { context.WriteLine("{0,-10} {1,-10} {2}", row.Count, row.Size, row.ClassName); totalCount += (ulong)row.Count; } } else { context.WriteLine("{0,-20} {1,-10} {2}", "Address", "Size", "Class Name"); foreach (var objPtr in readyForFinalization) { var type = heap.GetObjectType(objPtr); if (type == null || String.IsNullOrEmpty(type.Name)) { return; } context.WriteLink( String.Format("{0,-20:x16} {1,-10} {2}", objPtr, type.GetSize(objPtr), type.Name), String.Format("!do {0:x16}", objPtr) ); context.WriteLine(); ++totalCount; } } context.WriteLine("# of objects ready for finalization: {0}", totalCount); context.WriteLine("Memory reachable from these objects: {0}", heap.SizeReachableFromObjectSet(readyForFinalization).ToMemoryUnits()); var finalizerThread = context.Runtime.Threads.SingleOrDefault(t => t.IsFinalizer); if (finalizerThread != null && finalizerThread.BlockingObjects.Count > 0) { context.WriteLine(); context.WriteLine("The finalizer thread is blocked! Blocking objects:"); foreach (var blockingObject in finalizerThread.BlockingObjects) { context.Write("\t{0} ", blockingObject.Reason); string objHex = String.Format("{0:x16}", blockingObject.Object); context.WriteLink(objHex, "!do " + objHex); context.WriteLine(); } context.WriteLine("Blocked at:"); foreach (var frame in finalizerThread.StackTrace.Take(3)) { context.WriteLine("\t" + frame.DisplayString); } context.WriteLink( "\t... view full stack", String.Format("~ {0}; !clrstack", finalizerThread.ManagedThreadId)); context.WriteLine(); } }