Example #1
0
        public ulong GetTaskStateFromAddress(ulong address)
        {
            const string stateFieldName = "m_stateFlags";

            var type = _heap.GetObjectType(address);

            if ((type != null) && (type.Name.StartsWith("System.Threading.Tasks.Task")))
            {
                // could be other Task-prefixed types in the same namespace such as TaskCompletionSource
                if (type.GetFieldByName(stateFieldName) == null)
                {
                    return(0);
                }

                return((ulong)_heap.GetObject(address).ReadField <int>(stateFieldName));
            }

            return(0);
        }
Example #2
0
        private void CalculateTypeStatisticsPhase2(ClrHeap heap, Regex typesToReportStatisticsOnRegex, HashSet <ulong> markedObjects, TypeStatistics typeStatistics)
        {
            typeStatistics.MemoryProfilingStopwatch.Start();

            HashSet <ulong>   visitedObjects = new HashSet <ulong>();
            Queue <ClrObject> objectQueue    = new Queue <ClrObject>();

            // Start with exclusive = inclusive and walk the heap from roots looking for objects to subtract from this number.
            typeStatistics.ExclusiveRetainedBytes = typeStatistics.InclusiveRetainedBytes;

            foreach (ClrRoot root in heap.EnumerateRoots())
            {
                // Interested only in roots outside of our marked inclusive graph.
                if (!markedObjects.Contains(root.Object))
                {
                    ClrObject rootObj = heap.GetObject(root.Object);
                    objectQueue.Enqueue(rootObj);
                    visitedObjects.Add(root.Object);

                    while (objectQueue.Count > 0)
                    {
                        ClrObject obj = objectQueue.Dequeue();
                        if (obj.IsNull || obj.Type == null)
                        {
                            continue;
                        }

                        // We stop the walk when we see an object of a type we are reporting statistics on.
                        if (!typesToReportStatisticsOnRegex.IsMatch(obj.Type.Name))
                        {
                            if (markedObjects.Contains(obj.Address))
                            {
                                // Not an object of a type we are reporting statistics on but it is part of the inclusive object graph.
                                // This means that it must not be reported in the exclusive bytes.
                                typeStatistics.ExclusiveRetainedBytes -= obj.Size;
                                markedObjects.Remove(obj.Address);
                            }

                            // Follow all references.
                            foreach (var reference in obj.EnumerateObjectReferences())
                            {
                                if (!reference.IsNull && !visitedObjects.Contains(reference.Address))
                                {
                                    visitedObjects.Add(reference.Address);
                                    objectQueue.Enqueue(reference);
                                }
                            }
                        }
                    }
                }
            }

            typeStatistics.MemoryProfilingStopwatch.Stop();
        }
Example #3
0
    private void DebugObjectFields()
    {
        ClrHeap   heap      = Context.Heap;
        ClrObject clrObject = heap.GetObject(0x2910237db80);

        Debug.WriteLine("Name                      Dec Offset    Hex Offset    Type");
        foreach (var field in clrObject.Type.Fields)
        {
            Debug.WriteLine($"{field.Name,-25} {field.Offset,10}    {field.Offset,10:x}    {field.Type?.Name}");
        }
    }
Example #4
0
    static void Main(string[] args)
    {
        if (args.Length != 3)
        {
            Console.WriteLine("Usage: DumpDict [dump] [objref]");
            Environment.Exit(1);
        }

        if (ulong.TryParse(args[2], System.Globalization.NumberStyles.HexNumber, null, out ulong objAddr))
        {
            Console.WriteLine($"Could not parse object ref '{args[2]}'.");
            Environment.Exit(1);
        }

        string dumpFileName = args[0];
        string dacPath      = args[1];

        using DataTarget dataTarget = DataTarget.LoadDump(dumpFileName);
        using ClrRuntime runtime    = dataTarget.ClrVersions.Single().CreateRuntime();
        ClrHeap heap = runtime.Heap;

        ClrObject obj = heap.GetObject(objAddr);

        if (!obj.IsValidObject)
        {
            Console.WriteLine("Invalid object {0:X}", obj);
            return;
        }

        if (!obj.Type.Name.StartsWith("System.Collections.Generic.Dictionary"))
        {
            Console.WriteLine("Error: Expected object {0:X} to be a dictionary, instead it's of type '{1}'.");
            return;
        }

        // Get the entries field.
        ClrArray entries = obj.ReadObjectField("entries").AsArray();

        Console.WriteLine("{0,8} {1,16} : {2}", "hash", "key", "value");
        for (int i = 0; i < entries.Length; ++i)
        {
            ClrObject entry = entries.GetObjectValue(i);

            // TODO: Need to handle non-object references
            int       hashCode = entry.ReadField <int>("hashCode");
            ClrObject key      = entry.ReadObjectField("key");
            ClrObject value    = entry.ReadObjectField("value");

            Console.WriteLine($"{hashCode:x} {key} -> {value}");
        }
    }
Example #5
0
        public void PrevObject()
        {
            using DataTarget dt      = TestTargets.Types.LoadFullDump();
            using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime();
            ClrHeap heap = runtime.Heap;

            foreach (ClrSegment seg in heap.Segments)
            {
                ClrObject prev = heap.GetObject(seg.FirstObjectAddress);
                Assert.Equal(0ul, seg.GetPreviousObjectAddress(prev));

                foreach (ClrObject curr in seg.EnumerateObjects().Skip(1))
                {
                    Assert.Equal(prev.Address, seg.GetPreviousObjectAddress(curr));

                    prev = curr;
                }
            }
        }
Example #6
0
        /// <summary>
        /// Enumerates all objects reachable from GC roots in the given heap. Each object is returned exactly once.
        /// </summary>
        private IEnumerable <ClrObject> EnumerateRootedObjects(ClrHeap heap)
        {
            HashSet <ulong>   visitedObjects = new HashSet <ulong>();
            Queue <ClrObject> objectQueue    = new Queue <ClrObject>();

            foreach (ClrRoot root in heap.EnumerateRoots())
            {
                if (!visitedObjects.Contains(root.Object))
                {
                    ClrObject rootObj = heap.GetObject(root.Object);
                    objectQueue.Enqueue(rootObj);
                    visitedObjects.Add(root.Object);
                    if (rootObj.Type != null)
                    {
                        yield return(rootObj);
                    }

                    while (objectQueue.Count > 0)
                    {
                        ClrObject obj = objectQueue.Dequeue();
                        if (obj.IsNull || obj.Type == null)
                        {
                            continue;
                        }
                        // Follow all references.
                        foreach (var reference in obj.EnumerateObjectReferences())
                        {
                            if (!reference.IsNull && !visitedObjects.Contains(reference.Address))
                            {
                                objectQueue.Enqueue(reference);
                                visitedObjects.Add(reference.Address);
                                yield return(reference);
                            }
                        }
                    }
                }
            }
        }
Example #7
0
        public HeapIndex(ClrHeap heap)
        {
            // Evaluation stack
            Stack <ulong> eval = new Stack <ulong>();

            _roots            = new ObjectSet(heap);
            _walkableFromRoot = new ObjectSet(heap);

            foreach (var clrRoot in heap.EnumerateRoots())
            {
                _roots.Add(clrRoot.Object);
                eval.Push(clrRoot.Object);
            }

            while (eval.Count > 0)
            {
                // Pop an object, ignore it if we've seen it before.
                var address = eval.Pop();
                if (_walkableFromRoot.Contains(address))
                {
                    continue;
                }

                _walkableFromRoot.Add(address);

                // Grab the type. We will only get null here in the case of heap corruption.
                ClrType?type = heap.GetObjectType(address);
                if (type == null)
                {
                    continue;
                }

                // Now enumerate all objects that this object points to, add them to the
                // evaluation stack if we haven't seen them before.
                if (type.IsArray)
                {
                    EnumerateArrayElements(address);
                }
                else
                {
                    EnumerateFields(type, address);
                }
            }

            void EnumerateArrayElements(ulong address)
            {
                var obj           = heap.GetObject(address);
                var array         = obj.AsArray();
                var componentType = ((ClrmdArrayType)array.Type).ComponentType;

                if (componentType.IsObjectReference)
                {
                    foreach (var arrayElement in ArrayProxy.EnumerateObjectItems(array))
                    {
                        if (!arrayElement.IsNull)
                        {
                            AddReference(address, arrayElement.Address);
                            eval.Push(arrayElement.Address);
                        }
                    }
                }
                else
                {
                    // throw new NotSupportedException($"Enumerating array of {componentType} type is not supported");
                }
            }

            void EnumerateFields(ClrType?type, ulong address)
            {
                foreach (var instanceField in type.Fields)
                {
                    if (instanceField.IsObjectReference)
                    {
                        var fieldObject = instanceField.ReadObject(address, false);
                        if (!fieldObject.IsNull)
                        {
                            AddReference(address, fieldObject.Address);
                            eval.Push(fieldObject.Address);
                        }
                    }
                }
            }
        }
Example #8
0
        private static (uint, ulong) PopulateReferencedObjects(ClrHeap heap, ClrObjectModel clrObjModel)
        {
            // Evaluation stack
            var eval = new Stack <ulong>();
            var addressToClrObjectModel = new Dictionary <ulong, ClrObjectModel>
            {
                { clrObjModel.Address, clrObjModel }
            };
            // To make sure we don't count the same object twice, we'll keep a set of all objects
            // we've seen before.  Note the ObjectSet here is basically just "HashSet<ulong>".
            // However, HashSet<ulong> is *extremely* memory inefficient.  So we use our own to
            // avoid OOMs.
            var   currentObj = clrObjModel.Address;
            var   considered = new ObjectSet(heap);
            uint  count      = 0;
            ulong size       = 0;

            eval.Push(currentObj);

            while (eval.Count > 0)
            {
                // Pop an object, ignore it if we've seen it before.
                currentObj = eval.Pop();
                if (considered.Contains(currentObj))
                {
                    continue;
                }

                considered.Add(currentObj);

                // Grab the type. We will only get null here in the case of heap corruption.
                ClrType type = heap.GetObjectType(currentObj);
                if (type == null)
                {
                    continue;
                }

                count++;
                size += type.GetSize(currentObj);

                // Now enumerate all objects that this object points to, add them to the
                // evaluation stack if we haven't seen them before.
                type.EnumerateRefsOfObject(currentObj, delegate(ulong child, int offset)
                {
                    if (child != 0 && !considered.Contains(child))
                    {
                        var childObj = heap.GetObject(child);
                        ClrObjectModel childClrModel = null;
                        if (addressToClrObjectModel.ContainsKey(childObj))
                        {
                            childClrModel = addressToClrObjectModel[childObj];
                        }
                        else
                        {
                            childClrModel = new ClrObjectModel
                            {
                                TypeName          = childObj.Type.Name,
                                Address           = childObj,
                                ReferencedObjects = new List <ClrObjectModel>(),
                            };
                            addressToClrObjectModel[currentObj] = childClrModel;
                        }

                        addressToClrObjectModel[currentObj].ReferencedObjects.Add(childClrModel);
                        eval.Push(child);
                    }
                });
            }

            return(count, size);
        }
Example #9
0
        public static void LogTaskObjects(RuntimeContext runtimeContext, ILogger logger, bool includeCompleted,
                                          bool statOnly)
        {
            ClrHeap heap = runtimeContext.Heap;

            logger.LogInformation("Tasks:");
            // TODO System.Threading.Tasks.VoidTaskResult

            var taskQuery =
                from address in heap.EnumerateObjects()
                let type = address.Type
                           where type != null &&
                           !type.IsFree &&
                           type.Name != null && // TODO find better way
                           (type.Name == "System.Threading.Tasks.Task" ||
                            (type.Name.StartsWith("System.Threading.Tasks.Task<", StringComparison.Ordinal) &&
                             type.Name.EndsWith(">", StringComparison.Ordinal))) &&
                           (type.BaseType.Name == "System.Threading.Tasks.Task" ||
                            type.EnumerateInterfaces().Any(i => i.Name == "System.IAsyncResult"))
                           select new { Type = type, Address = address };

            var taskStat = new Dictionary <string, int>();

            foreach (var taskInfo in taskQuery)
            {
                var taskObject = heap.GetObject(taskInfo.Address);
                var taskProxy  = new TaskProxy(runtimeContext, taskObject);

                var taskIsCompleted = taskProxy.IsCompleted;
                if (!includeCompleted)
                {
                    if (taskIsCompleted)
                    {
                        continue;
                    }
                }

                if (statOnly)
                {
                    var taskTypeName = taskInfo.Type.Name !;
                    taskStat.IncrementValue(taskTypeName);
                }
                else
                {
                    logger.LogInformation($"{taskInfo.Address:X} {taskInfo.Type} taskIsCompleted={taskIsCompleted}");

                    var actionObject = taskObject.ReadObjectField("m_action");
                    if (!actionObject.IsNull && actionObject.Type.Name == "System.Action")
                    {
                        var ptr = actionObject.ReadValueTypeField("_methodPtr")
                                  .ReadField <UIntPtr>("m_value")
                                  .ToUInt64();

                        var clrMethod = heap.Runtime.GetMethodByInstructionPointer(ptr);
                        if (clrMethod != null)
                        {
                            logger.LogInformation($"method = {clrMethod.Name}");
                        }
                    }

                    foreach (var clrInstanceField in taskInfo.Type.Fields)
                    {
                        if (clrInstanceField.Name == "m_parent")
                        {
                            continue;
                        }
                        if (clrInstanceField.Name == "m_stateObject")
                        {
                            continue;
                        }
                        if (clrInstanceField.Name == "m_taskScheduler")
                        {
                            continue;
                        }
                        if (clrInstanceField.Name == "m_contingentProperties")
                        {
                            continue;
                        }
                        if (clrInstanceField.Name == "m_taskId")
                        {
                            continue;
                        }

                        //    logger.LogInformation($"{clrInstanceField.Name} ----------------------");

                        // var fieldValue = clrInstanceField.GetValue(taskInfo.Address);
                        if (clrInstanceField.IsPrimitive)
                        {
                            if (clrInstanceField.Name == "m_stateFlags")
                            {
                                var stateValue = clrInstanceField.Read <int>(taskInfo.Address, false);
                                logger.LogInformation($"{clrInstanceField.Name} = ");

                                foreach (var statePair in TaskProxy.TaskStates)
                                {
                                    if ((statePair.Key & stateValue) == statePair.Key)
                                    {
                                        logger.LogInformation($"{statePair.Value} |");
                                    }
                                }

                                continue;
                            }

                            // logger.LogInformation($"{clrInstanceField.Name} = {fieldValue}");
                            //                            continue;
                        }

                        //                        if (clrInstanceField.IsObjectReference)
                        //                        {
                        //                            var fieldAaddress = (ulong) fieldValue;
                        //                            if (fieldAaddress == 0)
                        //                            {
                        //                                logger.LogInformation($"{clrInstanceField.Name} = {{null}}");
                        //                                continue;
                        //                            }
                        //
                        //                            var fieldType = heap.GetObjectType(fieldAaddress);
                        //                            logger.LogInformation($"{clrInstanceField.Name} = {fieldAaddress:X} {fieldType}");
                        //                            if (fieldType.Name == "System.Action")
                        //                            {
                        //                                //heap.PrintObjectFields(fieldAaddress, fieldType, 1);
                        //
                        //                                var targetField = fieldType.GetFieldByName("_target");
                        //                                var targetFieldAddress = (ulong) targetField.GetValue(fieldAaddress);
                        //                                if (targetFieldAddress == 0)
                        //                                {
                        //                                    logger.LogInformation("\t_target = {null}");
                        //                                }
                        //                                else
                        //                                {
                        //                                    logger.LogInformation($"\t_target = {heap.GetObjectType(targetFieldAddress)}");
                        //
                        //                                    // TODO if it is "System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner" then take "m_stateMachine" field
                        //                                }
                        //
                        //                                var methodPtrField = fieldType.GetFieldByName("_methodPtr");
                        //                                var methodPtrValue = (long) methodPtrField.GetValue(fieldAaddress);
                        //
                        //                                var methodPtrWithOffset = 5UL + (ulong) methodPtrValue;
                        //                                heap.ReadPointer(methodPtrWithOffset + 2, out ulong someVal1);
                        //                                heap.ReadPointer(methodPtrWithOffset + 1, out ulong someVal2);
                        //                                heap.ReadPointer(methodPtrWithOffset + (someVal1 & 0xFF) * 8 + 3, out ulong baseMethodDesc);
                        //                                var offset = (someVal2 & 0xFF) * 8;
                        //                                var handle = baseMethodDesc + offset;
                        //                                var method = runtime.GetMethodByHandle(handle);
                        //
                        //                                //var methodByAddress = runtime.GetMethodByAddress(methodPtrValue);
                        //                                //var methodByHandle = runtime.GetMethodByHandle(methodPtrValue);
                        //
                        //                                //logger.LogInformation($"methodByAddress = {methodByAddress}");
                        //                                PrintIndention(1);
                        //                                logger.LogInformation($"methodByHandle = {method}");
                        //                            }
                        //
                        //                            continue;
                        //                        }
                        //
                        //                        if (clrInstanceField.IsValueClass)
                        //                        {
                        //                            logger.LogInformation($"{clrInstanceField.Name} {clrInstanceField.Type}");
                        //                            continue;
                        //                        }
                        //
                        //                        logger.LogInformation($"{clrInstanceField.Name} UNKNOWN TYPE");
                    }
                }
            }

            if (statOnly)
            {
                foreach (var i in taskStat.OrderByDescending(t => t.Value))
                {
                    logger.LogInformation($"{i.Key} {i.Value}");
                }
            }
        }