示例#1
0
        private void GCRootsImpl(GCRoot gcroot)
        {
            ClrHeap heap   = gcroot.Heap;
            ulong   target = heap.GetObjectsOfType("TargetType").Single();

            RootPath[] rootPaths = gcroot.EnumerateGCRoots(target, false, CancellationToken.None).ToArray();

            Assert.IsTrue(rootPaths.Length >= 2);

            foreach (RootPath rootPath in rootPaths)
            {
                AssertPathIsCorrect(heap, rootPath.Path.ToArray(), rootPath.Path.First().Address, target);
            }

            bool hasThread = false, hasStatic = false;

            foreach (RootPath rootPath in rootPaths)
            {
                if (rootPath.Root.Kind == GCRootKind.Pinning)
                {
                    hasStatic = true;
                }
                else if (rootPath.Root.Kind == GCRootKind.LocalVar)
                {
                    hasThread = true;
                }
            }

            Assert.IsTrue(hasThread);
            Assert.IsTrue(hasStatic);
        }
示例#2
0
        private static void GetKnownSourceAndTarget(ClrHeap heap, out ulong source, out ulong target)
        {
            ClrModule module   = heap.Runtime.GetMainModule();
            ClrType   mainType = module.GetTypeByName("GCRootTarget");

            source = mainType.GetStaticObjectValue("TheRoot").Address;
            target = heap.GetObjectsOfType("TargetType").Single();
        }
示例#3
0
        private ClrObject FindFirstInstanceOfType(ClrHeap heap, string typeName)
        {
            var type = heap.GetTypeByName(typeName);

            if (type is null)
            {
                throw new InvalidOperationException($"Could not find {typeName} in {TestTarget.Source} source.");
            }

            return(new ClrObject(heap.GetObjectsOfType(typeName).First(), type));
        }
示例#4
0
        private void GCRootsImpl(GCRoot gcroot)
        {
            ClrHeap heap   = gcroot.Heap;
            ulong   target = heap.GetObjectsOfType("TargetType").Single();

            GCRootsImpl(gcroot, heap, target, parallelism: 1, unique: false);
            GCRootsImpl(gcroot, heap, target, parallelism: 16, unique: false);

            GCRootsImpl(gcroot, heap, target, parallelism: 1, unique: true);
            GCRootsImpl(gcroot, heap, target, parallelism: 16, unique: true);
        }
示例#5
0
        public void EnumerateGCRefs()
        {
            using DataTarget dataTarget = TestTargets.GCRoot.LoadFullDump();
            using ClrRuntime runtime    = dataTarget.ClrVersions.Single().CreateRuntime();
            ClrHeap heap = runtime.Heap;

            ClrObject obj = heap.GetObjectsOfType("DoubleRef").Single();

            Assert.False(obj.IsNull);

            ValidateRefs(obj.EnumerateReferences().ToArray());
        }
示例#6
0
        public void EnumerateGCRefs()
        {
            using DataTarget dataTarget = TestTargets.GCRoot.LoadFullDump();
            ClrRuntime runtime = dataTarget.ClrVersions.Single().CreateRuntime();
            ClrHeap    heap    = runtime.Heap;

            ulong   obj  = heap.GetObjectsOfType("DoubleRef").Single();
            ClrType type = heap.GetObjectType(obj);

            ClrObject[] refs = type.EnumerateObjectReferences(obj).ToArray();
            ValidateRefs(refs);
        }
示例#7
0
        public void GCRootsIndirectHandles()
        {
            using DataTarget dataTarget = TestTargets.GCRoot2.LoadFullDump();

            ClrRuntime runtime = dataTarget.ClrVersions.Single().CreateRuntime();
            ClrHeap    heap    = runtime.Heap;
            GCRoot     gcroot  = new GCRoot(heap);

            ulong target = heap.GetObjectsOfType("IndirectTarget").Single();

            _ = Assert.Single(gcroot.EnumerateGCRoots(target, unique: true, CancellationToken.None));

            Assert.Equal(2, gcroot.EnumerateGCRoots(target, unique: false, CancellationToken.None).Count());
        }
示例#8
0
        public void GCRoots()
        {
            using DataTarget dataTarget = TestTargets.GCRoot.LoadFullDump();
            using ClrRuntime runtime    = dataTarget.ClrVersions.Single().CreateRuntime();
            ClrHeap heap   = runtime.Heap;
            GCRoot  gcroot = new GCRoot(heap);

            ulong target = heap.GetObjectsOfType("TargetType").Single();

            GCRootsImpl(gcroot, heap, target, parallelism: 1, unique: false);
            GCRootsImpl(gcroot, heap, target, parallelism: 16, unique: false);

            GCRootsImpl(gcroot, heap, target, parallelism: 1, unique: true);
            GCRootsImpl(gcroot, heap, target, parallelism: 16, unique: true);
        }
示例#9
0
        private void GCRootsImpl(GCRoot gcroot)
        {
            ClrHeap heap   = gcroot.Heap;
            ulong   target = heap.GetObjectsOfType("TargetType").Single();

            GCRootPath[] rootPaths = gcroot.EnumerateGCRoots(target, unique: false, 1, CancellationToken.None).ToArray();
            CheckRootPaths(heap, target, rootPaths, mustContainStatic: true);

            rootPaths = gcroot.EnumerateGCRoots(target, unique: false, 16, CancellationToken.None).ToArray();
            CheckRootPaths(heap, target, rootPaths, mustContainStatic: true);

            rootPaths = gcroot.EnumerateGCRoots(target, unique: true, 1, CancellationToken.None).ToArray();
            CheckRootPaths(heap, target, rootPaths, mustContainStatic: true);

            // In the case where we say we only want unique rooting chains AND we want to look in parallel,
            // we cannot guarantee that we will pick the static roots over the stack ones.  Hence we don't
            // ensure that the static variable is enumerated.
            rootPaths = gcroot.EnumerateGCRoots(target, unique: true, 16, CancellationToken.None).ToArray();
            CheckRootPaths(heap, target, rootPaths, mustContainStatic: false);
        }
示例#10
0
        public void EnumerateGCRefs()
        {
            using DataTarget dataTarget = TestTargets.GCRoot.LoadFullDump();
            using ClrRuntime runtime    = dataTarget.ClrVersions.Single().CreateRuntime();
            ClrHeap heap = runtime.Heap;

            ClrObject doubleRef = heap.GetObjectsOfType("DoubleRef").Single();

            Assert.False(doubleRef.IsNull);

            ClrObject[] refs = doubleRef.EnumerateReferences().ToArray();

            // Should contain one SingleRef and one TripleRef object.
            Assert.Equal(2, refs.Length);

            Assert.Equal(1, refs.Count(r => r.Type.Name == "SingleRef"));
            Assert.Equal(1, refs.Count(r => r.Type.Name == "TripleRef"));

            foreach (ClrObject obj in refs)
            {
                Assert.NotEqual(0ul, obj.Address);
                Assert.Equal(obj.Type.Heap.GetObjectType(obj.Address), obj.Type);
            }
        }
示例#11
0
        private static void GetAllStateMachines(DebuggerContext context, ClrHeap heap, List <AsyncStateMachine> allStateMachines, Dictionary <ulong, AsyncStateMachine> knownStateMachines)
        {
            foreach (var obj in heap.GetObjectsOfType("System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner"))
            {
                try
                {
                    var stateMachine = obj.ReadObjectField("m_stateMachine");
                    if (!knownStateMachines.ContainsKey(stateMachine.Address))
                    {
                        try
                        {
                            var state = stateMachine.ReadField <int>("<>1__state");
                            if (state >= -1)
                            {
                                ClrObject taskField    = default(ClrObject);
                                var       asyncBuilder = stateMachine.TryGetValueClassField("<>t__builder");
                                if (asyncBuilder.HasValue)
                                {
                                    while (asyncBuilder.HasValue)
                                    {
                                        taskField = asyncBuilder.TryGetObjectField("m_task");
                                        if (!taskField.IsNull)
                                        {
                                            break;
                                        }

                                        asyncBuilder = asyncBuilder.TryGetValueClassField("m_builder");
                                    }
                                }
                                else
                                {
                                    // CLR debugger may not be able to access t__builder, when NGEN assemblies are being used, and the type of the field could be lost.
                                    // Our workaround is to pick up the first Task object referenced by the state machine, which seems to be correct.
                                    // That function works with the raw data structure (like how GC scans the object, so it doesn't depend on symbols.
                                    foreach (ClrObject referencedObject in stateMachine.EnumerateReferences(true))
                                    {
                                        if (!referencedObject.IsNull && referencedObject.Type is object)
                                        {
                                            if (string.Equals(referencedObject.Type.Name, "System.Threading.Tasks.Task", StringComparison.Ordinal) || string.Equals(referencedObject.Type.BaseType?.Name, "System.Threading.Tasks.Task", StringComparison.Ordinal))
                                            {
                                                taskField = referencedObject;
                                                break;
                                            }
                                        }
                                    }
                                }

                                var asyncState = new AsyncStateMachine(state, stateMachine, taskField);
                                allStateMachines.Add(asyncState);
                                knownStateMachines.Add(stateMachine.Address, asyncState);

                                if (stateMachine.Type is object)
                                {
                                    foreach (var method in stateMachine.Type.Methods)
                                    {
                                        if (method.Name == "MoveNext" && method.NativeCode != ulong.MaxValue)
                                        {
                                            asyncState.CodeAddress = method.NativeCode;
                                        }
                                    }
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            context.Output.WriteLine($"Fail to process state machine {stateMachine.Address:x} Type:'{stateMachine.Type?.Name}' Module:'{stateMachine.Type?.Module?.Name}' Error: {ex.Message}");
                        }
                    }
                }
                catch (Exception ex)
                {
                    context.Output.WriteLine($"Fail to process AsyncStateMachine Runner {obj.Address:x} Error: {ex.Message}");
                }
            }
        }
示例#12
0
        private static void GetAllStateMachines(DebuggerContext context, ClrHeap heap, List <AsyncStateMachine> allStateMachines, Dictionary <ulong, AsyncStateMachine> knownStateMachines)
        {
            foreach (ClrObject obj in heap.GetObjectsOfType("System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner"))
            {
                try
                {
                    ClrObject stateMachine = obj.ReadObjectField("m_stateMachine");
                    if (!knownStateMachines.ContainsKey(stateMachine.Address))
                    {
                        try
                        {
                            var state = stateMachine.ReadField <int>("<>1__state");
                            if (state >= -1)
                            {
                                ClrObject    taskField    = default(ClrObject);
                                ClrValueType?asyncBuilder = stateMachine.TryGetValueClassField("<>t__builder");
                                if (asyncBuilder.HasValue)
                                {
                                    while (asyncBuilder.HasValue)
                                    {
                                        taskField = asyncBuilder.TryGetObjectField("m_task");
                                        if (!taskField.IsNull)
                                        {
                                            break;
                                        }

                                        ClrValueType?nextAsyncBuilder = asyncBuilder.TryGetValueClassField("m_builder");
                                        if (nextAsyncBuilder is null)
                                        {
                                            asyncBuilder = asyncBuilder.TryGetValueClassField("_methodBuilder");
                                        }
                                        else
                                        {
                                            asyncBuilder = nextAsyncBuilder;
                                        }
                                    }
                                }
                                else
                                {
                                    // CLR debugger may not be able to access t__builder, when NGEN assemblies are being used, and the type of the field could be lost.
                                    // Our workaround is to pick up the first Task object referenced by the state machine, which seems to be correct.
                                    // That function works with the raw data structure (like how GC scans the object, so it doesn't depend on symbols.
                                    //
                                    // However, one problem of that is we can pick up tasks from other reference fields of the same structure. So, we go through fields which we have symbols
                                    // and remember references encounted, and we skip them when we go through GC references.
                                    // Note: we can do better by going through other value structures, and extract references from them here, which we can consider when we have a real scenario.
                                    var previousReferences = new Dictionary <ulong, int>();
                                    if (stateMachine.Type?.GetFieldByName("<>t__builder") is not null)
                                    {
                                        foreach (ClrInstanceField field in stateMachine.Type.Fields)
                                        {
                                            if (string.Equals(field.Name, "<>t__builder", StringComparison.Ordinal))
                                            {
                                                break;
                                            }

                                            if (field.IsObjectReference)
                                            {
                                                ClrObject referencedValue = field.ReadObject(stateMachine.Address, interior: false);
                                                if (!referencedValue.IsNull)
                                                {
                                                    if (previousReferences.TryGetValue(referencedValue.Address, out int refCount))
                                                    {
                                                        previousReferences[referencedValue.Address] = refCount + 1;
                                                    }
                                                    else
                                                    {
                                                        previousReferences[referencedValue.Address] = 1;
                                                    }
                                                }
                                            }
                                        }
                                    }

                                    foreach (ClrObject referencedObject in stateMachine.EnumerateReferences(true))
                                    {
                                        if (!referencedObject.IsNull)
                                        {
                                            if (previousReferences.TryGetValue(referencedObject.Address, out int refCount) && refCount > 0)
                                            {
                                                if (refCount == 1)
                                                {
                                                    previousReferences.Remove(referencedObject.Address);
                                                }
                                                else
                                                {
                                                    previousReferences[referencedObject.Address] = refCount - 1;
                                                }

                                                continue;
                                            }
                                            else if (previousReferences.Count > 0)
                                            {
                                                continue;
                                            }

                                            if (referencedObject.Type is object &&
                                                (string.Equals(referencedObject.Type.Name, "System.Threading.Tasks.Task", StringComparison.Ordinal) || string.Equals(referencedObject.Type.BaseType?.Name, "System.Threading.Tasks.Task", StringComparison.Ordinal)))
                                            {
                                                taskField = referencedObject;
                                                break;
                                            }
                                        }
                                    }
                                }

                                var asyncState = new AsyncStateMachine(state, stateMachine, taskField);
                                allStateMachines.Add(asyncState);
                                knownStateMachines.Add(stateMachine.Address, asyncState);

                                if (stateMachine.Type is object)
                                {
                                    foreach (ClrMethod?method in stateMachine.Type.Methods)
                                    {
                                        if (method.Name == "MoveNext" && method.NativeCode != ulong.MaxValue)
                                        {
                                            asyncState.CodeAddress = method.NativeCode;
                                        }
                                    }
                                }
                            }
                        }
#pragma warning disable CA1031 // Do not catch general exception types
                        catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                        {
                            context.Output.WriteLine($"Fail to process state machine {stateMachine.Address:x} Type:'{stateMachine.Type?.Name}' Module:'{stateMachine.Type?.Module?.Name}' Error: {ex.Message}");
                        }
                    }
                }
#pragma warning disable CA1031 // Do not catch general exception types
                catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                {
                    context.Output.WriteLine($"Fail to process AsyncStateMachine Runner {obj.Address:x} Error: {ex.Message}");
                }
            }
        }