private void DumpHandles(int GroupOnly = 0, string filterByType = null, string filterByObjType = null) { Dictionary <string, int> categories = new Dictionary <string, int>(); if (m_runtime.PointerSize == 8) { WriteLine("Handle Object Refs Type Object Type"); } else { WriteLine("Handle Object Refs Type Object Type"); } int i = 0; int c = 0; foreach (var handle in m_runtime.EnumerateHandles()) { if (!categories.ContainsKey(handle.HandleType.ToString())) { categories[handle.HandleType.ToString()] = 0; } categories[handle.HandleType.ToString()]++; ClrType obj = m_runtime.GetHeap().GetObjectType(handle.Object); if ( (String.IsNullOrEmpty(filterByType) || handle.HandleType.ToString().ToLowerInvariant().Contains(filterByType.ToLowerInvariant())) && (String.IsNullOrEmpty(filterByObjType) || obj.Name.ToLowerInvariant().Contains(filterByObjType.ToLowerInvariant())) ) { if (GroupOnly == 0) { Write("{0:%p} {1:%p}", handle.Address, handle.Object); Write(" {0,4} {1,-15}", handle.RefCount, handle.HandleType); Write(" {0}", obj.Name); WriteLine(""); } c++; } i++; } WriteLine(""); WriteLine("{0,8:#,#} Objects Listed or met the criteria", c); if (c != i) { WriteLine("{0,8:#,#} Objects Skipped by the filter(s)", i - c); } WriteLine(""); WriteLine("{0,8:#,#} Handle(s) found in {1} categories", i, categories.Keys.Count); foreach (var cat in categories.Keys) { Write("{0,8:#,#} ", categories[cat]); Write("<link cmd=\"!wcghandle -handletype {0}\">{0}</link>", cat); WriteLine(" found"); } WriteLine(""); }
private static void PrintGCHandles(ClrRuntime runtime, StreamWriter sw) { foreach (ClrHandle handle in runtime.EnumerateHandles()) { string objectType = runtime.Heap.GetObjectType(handle.Object).Name; sw.WriteLine("{0,12:X} {1,12:X} {2,12} {3}", handle.Address, handle.Object, handle.HandleType, objectType); } }
private void DumpGcHandles(ClrRuntime runtime) { Log.Information("GC Handles:"); foreach (var handle in runtime.EnumerateHandles()) { var objectType = runtime.Heap.GetObjectType(handle.Object).Name; Log.Information("{address,12:X} {object,12:X} {type,12} {objectType}", handle.Address, handle.Object, handle.Type, objectType); } }
// OUTPUT SAMPLE // ------------------ // 201E53A10D0 201E5561360 System.String System.String // 201E53A10D8 201E5561360 System.String System.String // 201E53A10E0 201E5561360 System.String System.String // 201E53A10E8 201E5561360 System.String System.String // ------------------ public void ShowGcHandles(ClrRuntime runtime) { var heap = runtime.Heap; foreach (ClrHandle handle in runtime.EnumerateHandles()) { string objectType = heap.GetObjectType(handle.Object).Name; Console.WriteLine("{0,12:X} {1,12:X} {2,12} {3}", handle.Address, handle.Object, handle.Type, objectType); } Console.WriteLine(); }
public void EnsureEnumerationStability() { // I made some changes to v4.5 handle enumeration to enumerate handles out faster. // This test makes sure I have a stable enumeration. using (DataTarget dt = TestTargets.GCHandles.LoadFullDump()) { ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime(); List <ClrHandle> handles = new List <ClrHandle>(runtime.EnumerateHandles()); int i = 0; foreach (var hnd in runtime.EnumerateHandles()) { Assert.Equal(handles[i++], hnd); } // We create at least this many handles in the test, plus the runtime uses some. Assert.True(handles.Count > 4); } }
public void EnsureAllItemsAreUnique() { // Making sure that handles are returned only once HashSet <ClrHandle> handles = new HashSet <ClrHandle>(); using DataTarget dt = TestTargets.GCHandles.LoadFullDump(); using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime(); foreach (ClrHandle handle in runtime.EnumerateHandles()) { Assert.True(handles.Add(handle)); } // Make sure we had at least one AsyncPinned handle Assert.Contains(handles, h => h.HandleKind == ClrHandleKind.AsyncPinned); }
public void EnsureAllItemsAreUnique() { // Making sure that handles are returned only once var handles = new HashSet <ClrHandle>(); using (DataTarget dt = TestTargets.GCHandles.LoadFullDump()) { ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime(); foreach (var handle in runtime.EnumerateHandles()) { Assert.IsTrue(handles.Add(handle)); } // Make sure we had at least one AsyncPinned handle Assert.IsTrue(handles.Any(h => h.HandleType == HandleType.AsyncPinned)); } }
public void RuntimeTests(TestHost host) { // The current Linux test assets are not alpine/musl if (OS.IsAlpine) { throw new SkipTestException("Not supported on Alpine Linux"); } var runtimeService = host.Target.Services.GetService <IRuntimeService>(); Assert.NotNull(runtimeService); var contextService = host.Target.Services.GetService <IContextService>(); Assert.NotNull(contextService); Assert.NotNull(contextService.GetCurrentRuntime()); foreach (ImmutableDictionary <string, TestDataReader.Value> runtimeData in host.TestData.Runtimes) { if (runtimeData.TryGetValue("Id", out int id)) { IRuntime runtime = runtimeService.EnumerateRuntimes().FirstOrDefault((r) => r.Id == id); Assert.NotNull(runtime); runtimeData.CompareMembers(runtime); ClrInfo clrInfo = runtime.Services.GetService <ClrInfo>(); Assert.NotNull(clrInfo); ClrRuntime clrRuntime = runtime.Services.GetService <ClrRuntime>(); Assert.NotNull(clrRuntime); Assert.NotEmpty(clrRuntime.AppDomains); Assert.NotEmpty(clrRuntime.Threads); Assert.NotEmpty(clrRuntime.EnumerateModules()); if (!host.DumpFile.Contains("Triage")) { Assert.NotEmpty(clrRuntime.EnumerateHandles()); } } } }
public void EnsureEnumerationStability() { // I made some changes to v4.5 handle enumeration to enumerate handles out faster. // This test makes sure I have a stable enumeration. using (DataTarget dt = TestTargets.GCHandles.LoadFullDump()) { ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime(); List <ClrHandle> handles = new List <ClrHandle>(); bool cont; do { cont = false; int i = 0; foreach (var hnd in runtime.EnumerateHandles()) { if (i > handles.Count) { break; } if (i == handles.Count) { cont = true; handles.Add(hnd); break; } Assert.AreEqual(handles[i++], hnd); } } while (cont); // We create at least this many handles in the test, plus the runtime uses some. Assert.IsTrue(handles.Count > 4); } }
static void Main(string[] args) { Console.WriteLine("Hello World!"); var crashDumpPath = "../../artefacts/core_20200503_003216"; using (DataTarget dataTarget = DataTarget.LoadDump(crashDumpPath)) { foreach (ClrInfo version in dataTarget.ClrVersions) { Console.WriteLine("Found CLR Version: " + version.Version); // This is the data needed to request the dac from the symbol server: DacInfo dacInfo = version.DacInfo; Console.WriteLine("Filesize: {0:X}", dacInfo.IndexFileSize); Console.WriteLine("Timestamp: {0:X}", dacInfo.IndexTimeStamp); Console.WriteLine("Dac File: {0}", dacInfo.PlatformSpecificFileName); // If we just happen to have the correct dac file installed on the machine, // the "LocalMatchingDac" property will return its location on disk: string dacLocation = version.DacInfo.LocalDacPath;; if (!string.IsNullOrEmpty(dacLocation)) { Console.WriteLine("Local dac location: " + dacLocation); } ClrInfo runtimeInfo = dataTarget.ClrVersions[0]; // just using the first runtime ClrRuntime runtime = runtimeInfo.CreateRuntime(); // You may also download the dac from the symbol server, which is covered // in a later section of this tutorial. foreach (ClrAppDomain domain in runtime.AppDomains) { Console.WriteLine("ID: {0}", domain.Id); Console.WriteLine("Name: {0}", domain.Name); Console.WriteLine("Address: {0}", domain.Address); foreach (ClrModule module in domain.Modules) { Console.WriteLine("Module: {0}", module.Name); } foreach (ClrThread thread in runtime.Threads) { if (!thread.IsAlive) { continue; } Console.WriteLine("Thread {0:X}:", thread.OSThreadId); foreach (ClrStackFrame frame in thread.EnumerateStackTrace()) { Console.WriteLine("Stack Name: " + frame.ToString()); Console.WriteLine("{0,12:X} {1,12:X} {2}", frame.StackPointer, frame.InstructionPointer, frame); } Console.WriteLine(); Console.WriteLine("{0,12} {1,12} {2,12} {3,12} {4,4} {5}", "Start", "End", "CommittedMemory", "ReservedMemory", "Heap", "Type"); foreach (ClrSegment segment in runtime.Heap.Segments) { string type; if (segment.IsEphemeralSegment) { type = "Ephemeral"; } else if (segment.IsLargeObjectSegment) { type = "Large"; } else { type = "Gen2"; } Console.WriteLine("{0,12:X} {1,12:X} {2,12:X} {3,12:X} {4,4} {5}", segment.Start, segment.End, segment.CommittedMemory, segment.ReservedMemory, segment.LogicalHeap, type); } foreach (var item in (from seg in runtime.Heap.Segments group seg by seg.LogicalHeap into g orderby g.Key select new { Heap = g.Key, Size = g.Sum(p => (uint)p.Length) })) { Console.WriteLine("Heap {0,2}: {1:n0} bytes", item.Heap, item.Size); } } foreach (var handle in runtime.EnumerateHandles()) { string objectType = runtime.Heap.GetObjectType(handle.Object).Name; Console.WriteLine("{0,12:X} {1,12:X} {2,12} {3}", handle.Address, handle.Object, handle.GetType(), objectType); } if (!runtime.Heap.CanWalkHeap) { Console.WriteLine("Cannot walk the heap!"); } else { foreach (ClrSegment seg in runtime.Heap.Segments) { for (ulong obj = seg.FirstObjectAddress; obj != 0; obj = seg.GetNextObjectAddress(obj)) { ClrType type = runtime.Heap.GetObjectType(obj); // If heap corruption, continue past this object. if (type == null) { continue; } int size = type.StaticSize; Console.WriteLine("{0,12:X} {1,8:n0} {2,1:n0} {3}", obj, size, seg.GetGeneration(obj), type.Name); } } } // https://github.com/microsoft/clrmd/blob/master/doc/WalkingTheHeap.md#walking-objects-without-walking-the-segments if (!runtime.Heap.CanWalkHeap) { Console.WriteLine("Cannot walk the heap!"); } else { foreach (ulong obj in runtime.Heap.EnumerateObjects()) { ClrType type = runtime.Heap.GetObjectType(obj); // If heap corruption, continue past this object. if (type == null) { continue; } int size = type.StaticSize; Console.WriteLine("{0,12:X} {1,8:n0} {2,1:n0} {3}", obj, size, type.GCDesc, type.Name); } } } } } }
public IEnumerable <HandleInfo> GetAllHandles() { return(runtime.EnumerateHandles().Select(h => new HandleInfo { ClrHandle = h })); }
public IEnumerable <ClrHandle> GCHandles() { return(_runtime.EnumerateHandles()); }
public void EnumerateGCHandles(out IMDHandleEnum ppEnum) { ppEnum = new MDHandleEnum(m_runtime.EnumerateHandles()); }
private void InspectProcess(int pId) { using (DataTarget target = DataTarget.AttachToProcess(pId, 10000)) { ShowCLRRuntimeInformation(target); ClrRuntime runtime = target.ClrVersions.First().CreateRuntime(); LoadThreads(runtime); Dictionary <string, TypeEntry> types = new Dictionary <string, TypeEntry>(); Dictionary <string, StringInfor> stringCount = new Dictionary <string, StringInfor>(); ClrHeap heap = runtime.Heap; var finalizerQueueObjects = runtime.EnumerateFinalizerQueueObjectAddresses().ToList(); var pinnedObjects = runtime.EnumerateHandles().Where(h => h.IsPinned).Select(h => h.Object).ToList(); var blockingObjects = heap.EnumerateBlockingObjects().Select(x => x.Object).ToList(); //var blockingObjects = runtime.Threads.SelectMany(x => x.BlockingObjects).Select(x => x.Object).ToList(); foreach (ulong obj in heap.EnumerateObjects()) { ClrType type = heap.GetObjectType(obj); var size = type.GetSize(obj); var gen = heap.GetGeneration(obj); var isInFinalizerQueue = finalizerQueueObjects.Contains(obj); var isPinned = pinnedObjects.Contains(obj); var isBlocking = blockingObjects.Contains(obj); if (types.ContainsKey(type.Name)) { types[type.Name].Count++; types[type.Name].MinSize = Math.Min(types[type.Name].MinSize, size); types[type.Name].MaxSize = Math.Max(types[type.Name].MaxSize, size); types[type.Name].TotalSize += size; types[type.Name].Generation0 += gen == 0 ? 1 : 0; types[type.Name].Generation1 += gen == 1 ? 1 : 0; types[type.Name].Generation2 += gen == 2 ? 1 : 0; types[type.Name].FinalizerQueueCount += isInFinalizerQueue ? 1 : 0; types[type.Name].PinnedCount += isPinned ? 1 : 0; types[type.Name].BlockingCount += isBlocking ? 1 : 0; } else { types[type.Name] = new TypeEntry { Name = type.Name, Count = 1, MinSize = size, MaxSize = size, TotalSize = size, Generation0 = gen == 0 ? 1 : 0, Generation1 = gen == 1 ? 1 : 0, Generation2 = gen == 2 ? 1 : 0, FinalizerQueueCount = isInFinalizerQueue ? 1 : 0, PinnedCount = isPinned ? 1 : 0, BlockingCount = isBlocking ? 1 : 0, }; } if (type.IsString) { var text = (string)type.GetValue(obj); if (stringCount.ContainsKey(text)) { stringCount[text].Count++; stringCount[text].Generation0 += gen == 0 ? 1 : 0; stringCount[text].Generation1 += gen == 1 ? 1 : 0; stringCount[text].Generation2 += gen == 2 ? 1 : 0; } else { stringCount[text] = new StringInfor { Text = text, Count = 1, Generation0 = gen == 0 ? 1 : 0, Generation1 = gen == 1 ? 1 : 0, Generation2 = gen == 2 ? 1 : 0, }; } } } var sortOrder = heapObjectsGrid.SortOrder == SortOrder.Ascending ? ListSortDirection.Ascending : ListSortDirection.Descending; var sortCol = heapObjectsGrid.SortedColumn; int rowcount = 0; heapObjectsGrid.Rows.Clear(); foreach (var val in types.Where(x => x.Value.Count > 1)) { var infor = val.Value; DataGridViewRow gridrow = new DataGridViewRow(); gridrow.DefaultCellStyle.SelectionBackColor = Color.Black; if (rowcount % 2 > 0) { gridrow.DefaultCellStyle.BackColor = Color.AliceBlue; } rowcount++; DataGridViewTextBoxCell name = new DataGridViewTextBoxCell(); name.Value = infor.Name; gridrow.Cells.Add(name); DataGridViewTextBoxCell count = new DataGridViewTextBoxCell(); count.Style.Alignment = DataGridViewContentAlignment.BottomRight; count.Style.Format = "n0"; count.Value = infor.Count; gridrow.Cells.Add(count); DataGridViewTextBoxCell minSize = new DataGridViewTextBoxCell(); minSize.Style.Alignment = DataGridViewContentAlignment.BottomRight; minSize.Style.Format = "n0"; if (infor.MinSize >= 85000) { minSize.Style.ForeColor = Color.Orange; minSize.ToolTipText = "Large Object Heap"; } minSize.Value = infor.MinSize; gridrow.Cells.Add(minSize); DataGridViewTextBoxCell maxSize = new DataGridViewTextBoxCell(); maxSize.Style.Alignment = DataGridViewContentAlignment.BottomRight; maxSize.Style.Format = "n0"; if (infor.MaxSize >= 85000) { maxSize.Style.ForeColor = Color.Orange; maxSize.ToolTipText = "Large Object Heap"; } maxSize.Value = infor.MaxSize; gridrow.Cells.Add(maxSize); DataGridViewTextBoxCell totalSize = new DataGridViewTextBoxCell(); totalSize.Style.Alignment = DataGridViewContentAlignment.BottomRight; totalSize.Style.Format = "n0"; totalSize.Value = infor.TotalSize; gridrow.Cells.Add(totalSize); DataGridViewTextBoxCell generation0 = new DataGridViewTextBoxCell(); generation0.Value = infor.Generation0; generation0.Style.Alignment = DataGridViewContentAlignment.BottomRight; generation0.Style.Format = "n0"; gridrow.Cells.Add(generation0); DataGridViewTextBoxCell generation1 = new DataGridViewTextBoxCell(); generation1.Value = infor.Generation1; generation1.Style.Alignment = DataGridViewContentAlignment.BottomRight; generation1.Style.Format = "n0"; gridrow.Cells.Add(generation1); DataGridViewTextBoxCell generation2 = new DataGridViewTextBoxCell(); generation2.Value = infor.Generation2; generation2.Style.Alignment = DataGridViewContentAlignment.BottomRight; generation2.Style.Format = "n0"; gridrow.Cells.Add(generation2); DataGridViewTextBoxCell finalizerQueue = new DataGridViewTextBoxCell(); finalizerQueue.Value = infor.FinalizerQueueCount; finalizerQueue.Style.Alignment = DataGridViewContentAlignment.BottomRight; finalizerQueue.Style.Format = "n0"; gridrow.Cells.Add(finalizerQueue); DataGridViewTextBoxCell pinned = new DataGridViewTextBoxCell(); pinned.Value = infor.PinnedCount; pinned.Style.Alignment = DataGridViewContentAlignment.BottomRight; pinned.Style.Format = "n0"; gridrow.Cells.Add(pinned); DataGridViewTextBoxCell blocking = new DataGridViewTextBoxCell(); blocking.Value = infor.BlockingCount; blocking.Style.Alignment = DataGridViewContentAlignment.BottomRight; blocking.Style.Format = "n0"; gridrow.Cells.Add(blocking); heapObjectsGrid.Rows.Add(gridrow); } heapObjectsGrid.Columns[1].HeaderCell.ToolTipText = $"Total: { types.Values.Sum(x => x.Count).ToString("N0")} objects"; heapObjectsGrid.Columns[4].HeaderCell.ToolTipText = $"Total: {types.Values.Sum(x => (long)x.TotalSize).ToString("N0")} bytes"; if (sortCol != null) { heapObjectsGrid.Sort(sortCol, sortOrder); } // Strings Grid View: rowcount = 0; stringsGrid.Rows.Clear(); foreach (var str in stringCount) { DataGridViewRow gridrow = new DataGridViewRow(); gridrow.DefaultCellStyle.SelectionBackColor = Color.Black; if (rowcount % 2 > 0) { gridrow.DefaultCellStyle.BackColor = Color.AliceBlue; } rowcount++; DataGridViewTextBoxCell name = new DataGridViewTextBoxCell(); name.Value = str.Key; gridrow.Cells.Add(name); DataGridViewTextBoxCell length = new DataGridViewTextBoxCell(); length.Style.Alignment = DataGridViewContentAlignment.BottomRight; length.Style.Format = "n0"; length.Value = str.Key.Length; gridrow.Cells.Add(length); DataGridViewTextBoxCell count = new DataGridViewTextBoxCell(); count.Style.Alignment = DataGridViewContentAlignment.BottomRight; count.Style.Format = "n0"; count.Value = str.Value.Count; gridrow.Cells.Add(count); DataGridViewTextBoxCell generation0 = new DataGridViewTextBoxCell(); generation0.Value = str.Value.Generation0; generation0.Style.Alignment = DataGridViewContentAlignment.BottomRight; generation0.Style.Format = "n0"; gridrow.Cells.Add(generation0); DataGridViewTextBoxCell generation1 = new DataGridViewTextBoxCell(); generation1.Value = str.Value.Generation1; generation1.Style.Alignment = DataGridViewContentAlignment.BottomRight; generation1.Style.Format = "n0"; gridrow.Cells.Add(generation1); DataGridViewTextBoxCell generation2 = new DataGridViewTextBoxCell(); generation2.Value = str.Value.Generation2; generation2.Style.Alignment = DataGridViewContentAlignment.BottomRight; generation2.Style.Format = "n0"; gridrow.Cells.Add(generation2); stringsGrid.Rows.Add(gridrow); } } }
/// <summary> /// Enumerates a list of GC handles currently in the process. Note that this list may be incomplete /// depending on the state of the process when we attempt to walk the handle table. /// </summary> /// <returns>The list of GC handles in the process, NULL on catastrophic error.</returns> /// <inheritdoc /> public IEnumerable <IClrHandle> EnumerateHandles() => Runtime.EnumerateHandles().Select(Converter.Convert);