Example #1
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 #2
0
        public void OptimizedClassHistogram()
        {
            using (DataTarget dt = TestTargets.Types.LoadFullDump())
            {
                ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime();
                ClrHeap    heap    = runtime.Heap;

                // ensure that the optimized version is faster than the default one
                Stopwatch timing = new Stopwatch();
                var       notOptimizedStatistics  = new Dictionary <ClrType, TypeEntry>(32768);
                int       notOptimizedObjectCount = 0;

                // with an optimized version
                timing.Start();

                foreach (var objDetails in heap.EnumerateObjectDetails())
                {
                    ClrType type = objDetails.Item3;
                    ulong   size = objDetails.Item4;

                    TypeEntry entry;
                    if (!notOptimizedStatistics.TryGetValue(type, out entry))
                    {
                        entry = new TypeEntry()
                        {
                            TypeName = type.Name,
                            Size     = 0
                        };
                        notOptimizedStatistics[type] = entry;
                    }
                    entry.Count++;
                    entry.Size += size;
                    notOptimizedObjectCount++;
                }

                timing.Stop();
                var notOptimizedTime = TimeSpan.FromMilliseconds(timing.ElapsedMilliseconds);


                // with an non-optimized version
                var statistics  = new Dictionary <ClrType, TypeEntry>(32768);
                int objectCount = 0;
                timing.Restart();

                foreach (ulong objAddress in heap.EnumerateObjectAddresses())
                {
                    ClrType type = heap.GetObjectType(objAddress);
                    ulong   size = type.GetSize(objAddress);

                    TypeEntry entry;
                    if (!statistics.TryGetValue(type, out entry))
                    {
                        entry = new TypeEntry()
                        {
                            TypeName = type.Name,
                            Size     = 0
                        };
                        statistics[type] = entry;
                    }
                    entry.Count++;
                    entry.Size += size;
                    objectCount++;
                }

                timing.Stop();

                // check object count
                Assert.AreEqual(notOptimizedObjectCount, objectCount);

                // check heap content
                var types = notOptimizedStatistics.Keys;
                foreach (var type in types)
                {
                    var notOptimizedDetails = notOptimizedStatistics[type];
                    var details             = statistics[type];

                    Assert.AreEqual(notOptimizedDetails.TypeName, details.TypeName);
                    Assert.AreEqual(notOptimizedDetails.Count, details.Count);
                    Assert.AreEqual(notOptimizedDetails.Size, details.Size);
                }
                Assert.AreEqual(types.Count, statistics.Count);

                // checking that optimized is faster could be flaky
                // Assert.IsTrue(notOptimizedTime > TimeSpan.FromMilliseconds(timing.ElapsedMilliseconds));
            }
        }
Example #3
0
        private Dictionary<int, string> GetManagedThreadNames(ClrHeap heap)
        {
            var result = new Dictionary<int, string>();
            if (!heap.CanWalkHeap)
                return result;

            var threadObjects = from obj in heap.EnumerateObjectAddresses()
                                let type = heap.GetObjectType(obj)
                                where type != null && type.Name == "System.Threading.Thread"
                                select obj;
            var threadType = heap.GetTypeByName("System.Threading.Thread");
            var nameField = threadType.GetFieldByName("m_Name");
            var managedIdField = threadType.GetFieldByName("m_ManagedThreadId");

            foreach (var threadObject in threadObjects)
            {
                string name = (string)nameField.GetValue(threadObject);
                int id = (int)managedIdField.GetValue(threadObject);
                result.Add(id, name);
            }

            return result;
        }
Example #4
0
        private static KeyValuePair <bool, string> Enumerate()
        {
            //Attach to target process
            DataTarget dt = null;

            try
            {
                dt = DataTarget.AttachToProcess(targetPID, 10000, AttachFlag.NonInvasive);
            }
            catch (Exception e)
            {
                return(new KeyValuePair <bool, string>(false, e.ToString()));
            }

            //If no ClrVersions, return
            if (dt.ClrVersions.Count == 0)
            {
                return(new KeyValuePair <bool, string>(false, "[!] No Clr Versions detected"));
            }

#if DEBUG
            foreach (var ver in dt.ClrVersions)
            {
                Console.WriteLine("Clr Runtime Version Found: " + ver.Version.ToString());
            }
#endif

            ClrInfo Version = dt.ClrVersions[0];


            try
            {
                cRun = Version.CreateRuntime();
#if DEBUG
                Console.WriteLine("[+] Created Runtime");
#endif
            }
            catch (Exception e)
            {
#if DEBUG
                Console.WriteLine("[!] Failed to create runtime");
#endif
                return(new KeyValuePair <bool, string>(false, e.ToString()));
            }


            ClrHeap Heap = cRun.GetHeap();

            //if we can't walk the heap, return
            if (!Heap.CanWalkHeap)
            {
                return(new KeyValuePair <bool, string>(false, "[!] Unable to walk the heap"));
            }

            Console.WriteLine("[+] Walking the heap....");
            string m  = WildCardToRegWithQM("System.*");
            string m1 = WildCardToRegWithQM("_*");
            string m2 = WildCardToRegWithQM("Microsoft.*");
            foreach (ulong obj in Heap.EnumerateObjectAddresses())
            {
                //Grab each object, check if it has a simple value, if so, display it
                ClrType type = Heap.GetObjectType(obj);

                if (TypeName != null)
                {
                    if (type == null && type.Name == TypeName || Regex.IsMatch(type.Name, m) || Regex.IsMatch(type.Name, m1) || Regex.IsMatch(type.Name, m2) || type.Name == "Free")
                    {
                        continue;
                    }
                }
                else
                {
                    if (type == null || Regex.IsMatch(type.Name, m) || Regex.IsMatch(type.Name, m1) || Regex.IsMatch(type.Name, m2) || type.Name == "Free")
                    {
                        continue;
                    }
                }

                if (!type.IsPrimitive)
                {
#if DEBUG
                    Console.WriteLine("[+] Enumerating type: " + type.Name);
#endif
                    //if the type has a simple value, add the type and its value to the results
                    resultOutput.Append("\r\nType: " + type.Name + "\r\n\r\n");
                    //Enumerate all of the instance fields for the given type
                    if (showFields)
                    {
                        if (type.Fields != null)
                        {
                            GetInstanceFields(type.Fields, obj);
                        }
                    }


                    if (showstaticFields)
                    {
                        if (type.StaticFields != null)
                        {
                            GetStaticFields(type.StaticFields, cRun.AppDomains[0]);
                        }
                    }

                    if (showMethods)
                    {
                        if (type.Methods != null)
                        {
                            GetMethods(type.Methods);
                        }
                    }

                    if (referenceObjects)
                    {
                        resultOutput.Append("\r\nReferencedTypes\r\n\r\n");
                        List <ulong> referencedObjects = ClrMDHelper.GetReferencedObjects(Heap, obj);
                        foreach (ulong refObj in referencedObjects)
                        {
                            ClrType refObjType = Heap.GetObjectType(refObj);
                            if (refObjType == null || Regex.IsMatch(refObjType.Name, m) || Regex.IsMatch(refObjType.Name, m1) || Regex.IsMatch(refObjType.Name, m2) || refObjType.Name == "Free")
                            {
                                continue;
                            }

                            if (showFields)
                            {
                                if (refObjType.Fields != null)
                                {
                                    GetInstanceFields(refObjType.Fields, obj, fieldName);
                                }
                            }

                            if (showstaticFields)
                            {
                                if (refObjType.StaticFields != null)
                                {
                                    GetStaticFields(refObjType.StaticFields, cRun.AppDomains[0], fieldName);
                                }
                            }

                            if (showMethods)
                            {
                                if (refObjType.Methods != null)
                                {
                                    GetMethods(refObjType.Methods);
                                }
                            }
                        }
                    }
                }
            }

            return(new KeyValuePair <bool, string>(true, "[+] Successfully walked the heap."));
        }
Example #5
0
        private static void DumpRetention(DataTarget dataTarget, ClrInfo clrVersion, ClrRuntime runtime, ClrAppDomain appDomain, ClrHeap heap, string targetType)
        {
            var graph = new Graph();

            Console.WriteLine("## What's the retention path of the {0} object?", targetType);
            Console.WriteLine("");
            foreach (var ptr in heap.EnumerateObjectAddresses())
            {
                var type = heap.GetObjectType(ptr);
                if (type == null || type.Name != targetType)
                {
                    continue;
                }

                // Enumerate roots and try to find the current object
                var stack = new Stack <ulong>();
                foreach (var root in heap.EnumerateRoots())
                {
                    stack.Clear();
                    stack.Push(root.Object);
                    if (GetPathToObject(heap, ptr, stack, new HashSet <ulong>()))
                    {
                        // Print retention path
                        var depth           = 0;
                        var previousAddress = (ulong)0;
                        foreach (var address in stack)
                        {
                            var t = heap.GetObjectType(address);
                            if (t == null)
                            {
                                continue;
                            }

                            Console.WriteLine("{0} {1} - {2} - {3} bytes", new string('+', depth++), address, t.Name, t.GetSize(address));

                            graph.AddNode(address.ToString()).LabelText = $"{t.Name} ({address})";
                            if (previousAddress > 0 && !graph.Edges.Any(e => e.Source == previousAddress.ToString() && e.Target == address.ToString()))
                            {
                                graph.AddEdge(previousAddress.ToString(), address.ToString());
                            }
                            previousAddress = address;
                        }

                        Console.WriteLine();
                    }
                }
            }

            Console.ReadLine();

            // Render graph
            var width    = 1600;
            var renderer = new GraphRenderer(graph);

            renderer.CalculateLayout();
            var bitmap = new Bitmap(width, (int)(graph.Height * (width / graph.Width)), PixelFormat.Format32bppRgb);

            renderer.Render(bitmap);
            bitmap.Save("test.png");
            Process.Start("test.png");
        }
Example #6
0
        private IEnumerable <ulong> EnumerateManagedThreadpoolObjects()
        {
            _heap = _runtime.Heap;

            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 (ClrAppDomain 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;
                            do
                            {
                                if (!GetFieldObject(workQueueType, workQueue, "queueHead", out ClrType queueHeadType, out queueHead))
                                {
                                    break;
                                }

                                if (GetFieldObject(queueHeadType, queueHead, "nodes", out ClrType nodesType, out ulong 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;
                            }

                            if (!GetFieldObject(threadQueueType, threadQueue.Value, "m_array", out ClrType outerArrayType, out ulong 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;
                                }

                                if (!GetFieldObject(entryType, entry, "m_array", out ClrType arrayType, out ulong 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);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Example #7
0
        public static Node FindPathToTarget(ClrHeap heap, ClrRoot root)
        {
            ClrType type = heap.GetObjectType(root.Object);

            if (type == null)
            {
                return(null);
            }

            List <ulong> refList    = new List <ulong>();
            List <int>   offsetList = new List <int>();

            Node curr = new Node(root.Object, type);

            while (curr != null)
            {
                if (curr.Children == null)
                {
                    refList.Clear();
                    offsetList.Clear();

                    curr.Type.EnumerateRefsOfObject(curr.Object, delegate(ulong child, int offset)
                    {
                        if (child != 0)
                        {
                            refList.Add(child);
                            offsetList.Add(offset);
                        }
                    });

                    curr.Children = refList.ToArray();
                    curr.Offsets  = offsetList.ToArray();
                }
                else
                {
                    if (curr.Curr < curr.Children.Length)
                    {
                        ulong nextObj = curr.Children[curr.Curr];
                        int   offset  = curr.Offsets[curr.Curr];
                        curr.Curr++;

                        if (m_considered.Contains(nextObj))
                        {
                            continue;
                        }

                        m_considered.Add(nextObj);

                        Node next = null;
                        if (m_targets.TryGetValue(nextObj, out next))
                        {
                            curr.Next   = next;
                            next.Prev   = curr;
                            next.Offset = offset;

                            while (curr.Prev != null)
                            {
                                m_targets[curr.Object] = curr;
                                curr = curr.Prev;
                            }

                            m_targets[curr.Object] = curr;
                            return(curr);
                        }

                        type = heap.GetObjectType(nextObj);

                        if (type != null && type.ContainsPointers)
                        {
                            curr        = new Node(nextObj, type, curr);
                            curr.Offset = offset;
                        }
                    }
                    else
                    {
                        curr = curr.Prev;

                        if (curr != null)
                        {
                            curr.Next = null;
                        }
                    }
                }
            }

            return(null);
        }
Example #8
0
    public static void PrintDict(ClrRuntime runtime, string args)
    {
        bool  failed = false;
        ulong obj    = 0;

        try
        {
            obj    = Convert.ToUInt64(args, 16);
            failed = obj == 0;
        }
        catch (ArgumentException)
        {
            failed = true;
        }

        if (failed)
        {
            Console.WriteLine("Usage: !PrintDict <dictionary>");
            return;
        }

        ClrHeap heap = runtime.GetHeap();
        ClrType type = heap.GetObjectType(obj);

        if (type == null)
        {
            Console.WriteLine("Invalid object {0:X}", obj);
            return;
        }

        if (!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.
        ulong entries = type.GetFieldValue(obj, "entries");

        if (entries == 0)
        {
            return;
        }

        ClrType          entryArray     = heap.GetObjectType(entries);
        ClrType          arrayComponent = entryArray.ArrayComponentType;
        ClrInstanceField hashCodeField  = arrayComponent.GetFieldByName("hashCode");
        ClrInstanceField keyField       = arrayComponent.GetFieldByName("key");
        ClrInstanceField valueField     = arrayComponent.GetFieldByName("value");

        Console.WriteLine("{0,8} {1,16} : {2}", "hash", "key", "value");
        int len = entryArray.GetArrayLength(entries);

        for (int i = 0; i < len; ++i)
        {
            ulong arrayElementAddr = entryArray.GetArrayElementAddress(entries, i);

            int    hashCode = (int)hashCodeField.GetFieldValue(arrayElementAddr, true);
            object key      = keyField.GetFieldValue(arrayElementAddr, true);
            object value    = valueField.GetFieldValue(arrayElementAddr, true);

            key   = Format(heap, key);
            value = Format(heap, value);

            bool skip = key is ulong && (ulong)key == 0 && value is ulong && (ulong)value == 0;

            if (!skip)
            {
                Console.WriteLine("{0,8:X} {1,16} : {2}", hashCode, key, value);
            }
        }
    }
Example #9
0
        public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
        {
            if (IsNull())
            {
                result = new ClrNullValue(m_heap);
                return(true);
            }

            if (m_type.IsArray)
            {
                // Populate length for bounds check.
                if (m_len == -1)
                {
                    m_len = m_type.GetArrayLength(m_addr);
                }

                int index = GetIndexFromObjects(indexes);
                return(GetArrayValue(m_type, m_addr, index, out result));
            }

            // Dictionary
            if (IsDictionary())
            {
                if (indexes.Length != 1)
                {
                    throw new ArgumentException("Only one index is allowed for Dictionary indexing.");
                }

                dynamic          dict    = ((dynamic)this);
                dynamic          entries = dict.entries;
                ClrInstanceField key     = ((ClrType)entries).ArrayComponentType.GetFieldByName("key");

                // Two cases:  The key is an object or string, denoted by "System.__Canon", or it's a primitive.
                //             otherwise we don't support it.
                var keyType = key.Type;
                if (keyType.IsObjectReference)
                {
                    Debug.Assert(keyType.Name == "System.__Canon");
                    if (indexes[0].GetType() == typeof(string))
                    {
                        string index = (string)indexes[0];
                        int    len   = dict.count;
                        for (int i = 0; i < len; ++i)
                        {
                            if ((string)entries[i].key == index)
                            {
                                result = entries[i].value;
                                return(true);
                            }
                        }

                        throw new KeyNotFoundException();
                    }
                    else
                    {
                        ulong addr;
                        if (indexes[0].GetType() == typeof(long))
                        {
                            addr = (ulong)(long)indexes[0];
                        }
                        else if (indexes[0].GetType() == typeof(ulong))
                        {
                            addr = (ulong)indexes[0];
                        }
                        else
                        {
                            addr = (ulong)(dynamic)indexes[0];
                        }

                        int len = dict.count;
                        for (int i = 0; i < len; ++i)
                        {
                            if ((ulong)entries[i].key == addr)
                            {
                                result = entries[i].value;
                                return(true);
                            }
                        }
                    }
                }
                else if (keyType.IsPrimitive)
                {
                    object index = indexes[0];
                    if (index is ClrPrimitiveValue)
                    {
                        index = ((ClrPrimitiveValue)index).GetValue();
                    }
                    Type type = index.GetType();
                    int  len  = dict.count;
                    for (int i = 0; i < len; ++i)
                    {
                        ClrPrimitiveValue value = entries[i].key;
                        if (value.GetValue().Equals(index))
                        {
                            result = entries[i].value;
                            return(true);
                        }
                    }

                    throw new KeyNotFoundException();
                }
            }

            if (IsList())
            {
                int   index      = GetIndexFromObjects(indexes);
                var   itemsField = m_type.GetFieldByName("_items");
                ulong addr       = (ulong)itemsField.GetFieldValue(m_addr);

                // Populate length for bounds check.
                if (m_len == -1)
                {
                    var sizeField = m_type.GetFieldByName("_size");
                    m_len = (int)sizeField.GetFieldValue(m_addr);
                }

                // If type is null, then we've hit a dac bug.  Attempt to work around it,
                // but we'll have to give up if getting the object type directly doesn't work.
                ClrType type = itemsField.Type;
                if (type == null || type.ArrayComponentType == null)
                {
                    type = m_heap.GetObjectType(addr);
                    if (type == null || type.ArrayComponentType == null)
                    {
                        result = new ClrNullValue(m_heap);
                        return(true);
                    }
                }

                return(GetArrayValue(type, addr, index, out result));
            }

            throw new InvalidOperationException(string.Format("Object of type '{0}' is not indexable.", m_type.Name));
        }
Example #10
0
        public void TypeEqualityTest()
        {
            // This test ensures that only one ClrType is created when we have a type loaded into two different AppDomains with two different
            // method tables.

            const string TypeName = "Foo";

            using DataTarget dt      = TestTargets.AppDomains.LoadFullDump();
            using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime();
            ClrHeap heap = runtime.Heap;

            ClrType[] types = (from obj in heap.EnumerateObjects()
                               let t = heap.GetObjectType(obj.Address)
                                       where t.Name == TypeName
                                       orderby t.MethodTable
                                       select t).ToArray();

            Assert.Equal(2, types.Length);
            Assert.NotSame(types[0], types[1]);

            ClrType[] typesFromModule = (from module in runtime.EnumerateModules()
                                         let name = Path.GetFileNameWithoutExtension(module.Name)
                                                    where name.Equals("sharedlibrary", StringComparison.OrdinalIgnoreCase)
                                                    let type = module.GetTypeByName(TypeName)
                                                               select type).ToArray();

            Assert.Equal(2, typesFromModule.Length);
            Assert.NotSame(types[0], types[1]);
            Assert.NotEqual(types[0], types[1]);

            if (dt.CacheOptions.CacheTypes)
            {
                Assert.Same(types[0], typesFromModule[0]);
                Assert.Same(types[1], typesFromModule[1]);
            }
            else
            {
                Assert.Equal(types[0], typesFromModule[0]);
                Assert.Equal(types[1], typesFromModule[1]);
            }

            // Get new types
            runtime.FlushCachedData();

            ClrType[] newTypes = (from module in runtime.EnumerateModules()
                                  let name = Path.GetFileNameWithoutExtension(module.Name)
                                             where name.Equals("sharedlibrary", StringComparison.OrdinalIgnoreCase)
                                             let type = module.GetTypeByName(TypeName)
                                                        select type).ToArray();

            Assert.Equal(2, newTypes.Length);
            for (int i = 0; i < newTypes.Length; i++)
            {
                Assert.NotSame(typesFromModule[i], newTypes[i]);
                Assert.Equal(typesFromModule[i], newTypes[i]);
            }

            // Even though these are the same underlying type defined in sharedlibrary's metadata,
            // they have different MethodTables, Parent modules, and parent domains.  These do not
            // compare as equal.
            Assert.NotEqual(typesFromModule[0], typesFromModule[1]);
        }
Example #11
0
        public async Task <IEnumerable <object> > Execute(OperationModel model, CancellationToken token, object customeParameter)
        {
            //TODO: add support of local variables
            return(await DebuggerSession.Instance.ExecuteOperation(() =>
            {
                var result = new List <ClrStackDump>();
                foreach (var thread in DebuggerSession.Instance.Runtime.Threads)
                {
                    if (token.IsCancellationRequested)
                    {
                        break;
                    }

                    var stackDetails = new ClrStackDump();
                    stackDetails.StackFrames = new List <object>();
                    stackDetails.StackObjects = new List <object>();
                    foreach (var stackFrame in thread.StackTrace)
                    {
                        stackDetails.StackBase = thread.StackBase;
                        stackDetails.StackLimit = thread.StackLimit;
                        stackDetails.Exception = thread.CurrentException;
                        stackDetails.OSThreadID = thread.IsAlive ? thread.OSThreadId.ToString() : "XXX";
                        stackDetails.ManagedThreadId = thread.ManagedThreadId;
                        stackDetails.StackFrames.Add(
                            new
                        {
                            StackPointer = stackFrame.StackPointer,
                            InstructionPointer = stackFrame.InstructionPointer,
                            DisplayString = stackFrame.DisplayString,
                            //FileAndLine = source != null ? source.FilePath + ": " + source.LineNumber : "",
                            Method = stackFrame.Method
                        });
                    }

                    ClrHeap heap = DebuggerSession.Instance.Runtime.GetHeap();
                    var pointerSize = DebuggerSession.Instance.Runtime.PointerSize;

                    // address of TEB (thread execution block) + pointer size
                    ulong start = thread.StackBase;
                    // address of TEB (thread execution block) + pointer size * 2
                    ulong stop = thread.StackLimit;

                    // We'll walk these in pointer order.
                    if (start > stop)
                    {
                        ulong tmp = start;
                        start = stop;
                        stop = tmp;
                    }

                    // ptr is a stack address.
                    for (ulong ptr = start; ptr <= stop; ptr += (ulong)pointerSize)
                    {
                        HashSet <ulong> stackObjects = new HashSet <ulong>();

                        // fail to read the memory
                        if (!heap.ReadPointer(ptr, out ulong obj))
                        {
                            break;
                        }

                        // the object added already
                        if (!stackObjects.Add(obj))
                        {
                            continue;
                        }

                        // not an object
                        ClrType type = heap.GetObjectType(obj);
                        if (type == null)
                        {
                            continue;
                        }

                        // free space
                        if (type.IsFree)
                        {
                            continue;
                        }

                        // All good, add it
                        stackDetails.StackObjects.Add(
                            new
                        {
                            Address = ptr,
                            Object = obj,
                            Name = type.Name,
                            Value = new ClrObject(obj, type).Fields.Value
                        });
                    }
                    result.Add(stackDetails);
                }
                return result;
            }));
        }
Example #12
0
        static void Main(string[] args)
        {
            bool   stat;
            string dump, dac;

            if (!TryParseArgs(args, out dump, out dac, out stat))
            {
                Usage();
                Environment.Exit(1);
            }

            try
            {
                // Create a ClrRuntime instance from the dump and dac location.  The ClrRuntime
                // object represents a version of CLR loaded in the process.  It contains data
                // such as the managed threads in the process, the AppDomains in the process,
                // the managed heap, and so on.
                ClrRuntime runtime = CreateRuntime(dump, dac);

                // Walk the entire heap and build heap statistics in "stats".
                Dictionary <ClrType, Entry> stats = new Dictionary <ClrType, Entry>();

                if (!stat)
                {
                    Console.WriteLine("{0,16} {1,12} {2}", "Object", "Size", "Type");
                }

                // This is the way to walk every object on the heap:  Get the ClrHeap instance
                // from the runtime.  Walk every segment in heap.Segments, and use
                // ClrSegment.FirstObject and ClrSegment.NextObject to iterate through
                // objects on that segment.
                ClrHeap heap = runtime.GetHeap();
                foreach (ClrSegment seg in heap.Segments)
                {
                    for (ulong obj = seg.FirstObject; obj != 0; obj = seg.NextObject(obj))
                    {
                        // This gets the type of the object.
                        ClrType type = heap.GetObjectType(obj);
                        ulong   size = type.GetSize(obj);

                        // If the user didn't request "-stat", print out the object.
                        if (!stat)
                        {
                            Console.WriteLine("{0,16:X} {1,12:n0} {2}", obj, size, type.Name);
                        }

                        // Add an entry to the dictionary, if one doesn't already exist.
                        Entry entry = null;
                        if (!stats.TryGetValue(type, out entry))
                        {
                            entry       = new Entry();
                            entry.Name  = type.Name;
                            stats[type] = entry;
                        }

                        // Update the statistics for this object.
                        entry.Count++;
                        entry.Size += type.GetSize(obj);
                    }
                }

                // Now print out statistics.
                if (!stat)
                {
                    Console.WriteLine();
                }

                // We'll actually let linq do the heavy lifting.
                var sortedStats = from entry in stats.Values
                                  orderby entry.Size
                                  select entry;

                Console.WriteLine("{0,12} {1,12} {2}", "Size", "Count", "Type");
                foreach (var entry in sortedStats)
                {
                    Console.WriteLine("{0,12:n0} {1,12:n0} {2}", entry.Size, entry.Count, entry.Name);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Unhandled exception:");
                Console.WriteLine(ex);
            }
        }
Example #13
0
        public static void LogObjectFields(
            ClrHeap heap,
            ILogger logger,
            ulong address,
            ClrType objectType,
            ISet <string>?fieldList = null)
        {
            foreach (var clrInstanceField in objectType.Fields)
            {
                if (fieldList != null && !fieldList.Contains(clrInstanceField.Name))
                {
                    continue;
                }

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


                if (clrInstanceField.IsPrimitive)
                {
                    //                    if (clrInstanceField.Name == "m_stateFlags")
                    //                    {
                    //                        var stateValue = (int) fieldValue;
                    //                        logger.LogInformation($"{clrInstanceField.Name} = ");
                    //
                    //                        foreach (var statePair in TaskConstants.TASK_STATES)
                    //                        {
                    //                            if ((statePair.Key & stateValue) == statePair.Key)
                    //                            {
                    //                                logger.LogInformation($"{statePair.Value} |");
                    //                            }
                    //                        }
                    //
                    //                        logger.LogInformation();
                    //                        continue;
                    //                    }

                    // var fieldValue = clrInstanceField.read<????>(address);
                    // logger.LogInformation($"{clrInstanceField.Name} = {fieldValue}");
                    continue;
                }

                if (clrInstanceField.IsObjectReference)
                {
                    var value = "{null}";

                    var fieldValue = clrInstanceField.ReadObject(address, false);

                    if (fieldValue.Type !.IsString)
                    {
                        value = fieldValue.AsString();
                    }

                    switch (fieldValue)
                    {
                    case ulong fieldAddress:
                        if (fieldAddress != Address.Null.Value)
                        {
                            var fieldType = heap.GetObjectType(fieldAddress);
                            value = $"{fieldAddress:X} {fieldType}";
                        }

                        break;
                    }

                    logger.LogInformation($"{clrInstanceField.Name} = {value}");

                    //                    if (fieldType.Name == "System.Action")
                    //                    {
                    //                        var targetField = fieldType.GetFieldByName("_target");
                    //                        var targetFieldAddress = (ulong) targetField.GetValue(fieldAaddress);
                    //                        if (targetFieldAddress == 0)
                    //                        {
                    //                            logger.LogInformation("\t_target = {null}");
                    //                        }
                    //                        else
                    //                        {
                    //                            logger.LogInformation($"\t_target = {runtime.Heap.GetObjectType(targetFieldAddress)}");
                    //
                    //                            // TODO if it is "System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner" then take "m_stateMachine" field
                    //                        }
                    //                    }

                    continue;
                }

                if (clrInstanceField.IsValueType)
                {
                    logger.LogInformation(
                        $"{clrInstanceField.Name} {clrInstanceField.Type.GetClrTypeName()}");
                    continue;
                }

                logger.LogInformation($"{clrInstanceField.Name} UNKNOWN TYPE");
            }
        }
Example #14
0
        private static string Repr(ClrHeap heap, ulong addr)
        {
            var type = heap.GetObjectType(addr);

            return(Escape(type?.GetValue(addr)?.ToString() ?? string.Empty));
        }
Example #15
0
        GetClassValues(ClrHeap heap, ulong addr)
        {
            try
            {
                addr = Utils.RealAddress(addr);
                (ClrType type, ClrElementKind kind, ClrType rtType, ClrElementKind rtKind) = TypeExtractor.GetRealType(heap, addr);

                if (type == null)
                {
                    return("Object Value Error" + Constants.HeavyGreekCrossPadded + "Cannot find an instance." + Constants.HeavyGreekCrossPadded + "Heap cannot get object type at address: " + Utils.RealAddressString(addr), null, ClrElementKind.Unknown, (null, null, null, null, null));
                }
                var fldCnt = type.Fields.Count;

                var                fldTypes       = fldCnt == 0 ? Utils.EmptyArray <ClrType> .Value : new ClrType[fldCnt];
                var                fldKinds       = fldCnt == 0 ? Utils.EmptyArray <ClrElementKind> .Value : new ClrElementKind[fldCnt];
                var                objects        = fldCnt == 0 ? Utils.EmptyArray <object> .Value : new object[fldCnt];
                StructValues[]     structVals     = null;
                StructFieldsInfo[] structFldInfos = null;
                for (int i = 0; i < fldCnt; ++i)
                {
                    var fld     = type.Fields[i];
                    var fldType = fld.Type; // returns ClrElementKind.Unknown if fld.Type is null
                    var fldKind = TypeExtractor.GetElementKind(fldType);
                    if (fldKind == ClrElementKind.Unknown)
                    {
                        objects[i] = null;
                        continue; // nothing to do here, from MDR lib: There is
                                  // a bug in several versions of our debugging layer which causes this.
                    }
                    if (fldType == null || TypeExtractor.IsAmbiguousKind(fldKind))
                    {
                        var fldValObj = fld.GetValue(addr, type.IsValueClass, false);
                        if (fldValObj != null && fldValObj is ulong)
                        {
                            var t = heap.GetObjectType((ulong)fldValObj);
                            if (t != null)
                            {
                                fldType = t;
                                fldKind = TypeExtractor.GetElementKind(t);
                            }
                        }
                    }
                    fldTypes[i] = fldType;
                    fldKinds[i] = fldKind;
                    if (fldKind == ClrElementKind.Unknown)
                    {
                        continue;                                    // nothing to do here, from MDR lib: There is
                    }
                    // a bug in several versions of our debugging layer which causes this.
                    if (TypeExtractor.IsString(fldKind))
                    {
                        objects[i] = fld.GetValue(addr, false, true);
                    }
                    else if (TypeExtractor.IsObjectReference(fldKind))
                    {
                        object obj = fld.GetValue(addr, false, false);
                        if (obj != null && (ulong)obj != Constants.InvalidAddress)
                        {
                            var t = heap.GetObjectType((ulong)obj);
                            if (t != null)
                            {
                                var k = TypeExtractor.GetElementKind(t);
                                fldTypes[i] = t;
                                fldKinds[i] = k;
                            }
                        }

                        objects[i] = obj;
                    }
                    else if (TypeExtractor.IsEnum(fldKind))
                    {
                        objects[i] = ValueExtractor.GetEnumValueObject(addr, fld, false);
                    }
                    else if (fldType.IsPrimitive)
                    {
                        objects[i] = ValueExtractor.GetPrimitiveValueObject(addr, fld, false);
                    }
                    else if (TypeExtractor.IsKnownStruct(fldKind))
                    {
                        switch (TypeExtractor.GetSpecialKind(fldKind))
                        {
                        case ClrElementKind.DateTime:
                            objects[i] = ValueExtractor.GetDateTimePAF(addr, fld, false);
                            break;

                        case ClrElementKind.Guid:
                            objects[i] = ValueExtractor.GetGuid(addr, fld, false);
                            break;

                        case ClrElementKind.Decimal:
                            objects[i] = ValueExtractor.GetDecimalPAF(addr, fld, false);
                            break;

                        case ClrElementKind.TimeSpan:
                            objects[i] = ValueExtractor.TimeSpanValue(addr, fldType);
                            break;
                        }
                    }
                    else if (TypeExtractor.IsUnknownStruct(fldKind))
                    {
                        //StructFields sf = StructFields.GetStructFields(fldType);
                        //StructFieldsEx sfx = StructFieldsEx.GetStructFields(sf, fldType);
                        if (structFldInfos == null)
                        {
                            structFldInfos = new StructFieldsInfo[fldCnt];
                        }
                        ulong            saddr = fld.GetAddress(addr, true);
                        StructFieldsInfo sfi   = StructFieldsInfo.GetStructFields(fldType, heap, saddr);
                        structFldInfos[i] = sfi;
                        if (sfi != null)
                        {
                            if (structVals == null)
                            {
                                structVals = new StructValues[fldCnt];
                            }
                            structVals[i] = StructFieldsInfo.GetStructValues(sfi, heap, saddr);
                        }
                    }
                }

                return(null, type, kind, (fldTypes, fldKinds, objects, structFldInfos, structVals));
            }
            catch (Exception ex)
            {
                return(Utils.GetExceptionErrorString(ex), null, ClrElementKind.Unknown, (null, null, null, null, null));
            }
        }
Example #16
0
        public IClrObject ReadFromAddress(ClrHeap heap, ulong address)
        {
            var type = heap.GetObjectType(address);

            return(ReadFromAddress(type, address));
        }
Example #17
0
        static void Main(string[] args)
        {
            bool   stat, live;
            string dump, dac;

            if (!TryParseArgs(args, out dump, out dac, out stat, out live))
            {
                Usage();
                Environment.Exit(1);
            }

            try
            {
                ClrRuntime runtime = CreateRuntime(dump, dac);
                ClrHeap    heap    = runtime.GetHeap();

                ObjectSet liveObjs = null;
                if (live)
                {
                    liveObjs = GetLiveObjects(heap);
                }

                Dictionary <ClrType, Entry> stats = new Dictionary <ClrType, Entry>();

                if (!stat)
                {
                    Console.WriteLine("{0,16} {1,12} {2}", "Object", "Size", "Type");
                }

                foreach (ClrSegment seg in heap.Segments)
                {
                    for (ulong obj = seg.FirstObject; obj != 0; obj = seg.NextObject(obj))
                    {
                        if (live && !liveObjs.Contains(obj))
                        {
                            continue;
                        }

                        // This gets the type of the object.
                        ClrType type = heap.GetObjectType(obj);
                        ulong   size = type.GetSize(obj);

                        // If the user didn't request "-stat", print out the object.
                        if (!stat)
                        {
                            Console.WriteLine("{0,16:X} {1,12:n0} {2}", obj, size, type.Name);
                        }

                        // Add an entry to the dictionary, if one doesn't already exist.
                        Entry entry = null;
                        if (!stats.TryGetValue(type, out entry))
                        {
                            entry       = new Entry();
                            entry.Name  = type.Name;
                            stats[type] = entry;
                        }

                        // Update the statistics for this object.
                        entry.Count++;
                        entry.Size += type.GetSize(obj);
                    }
                }

                // Now print out statistics.
                if (!stat)
                {
                    Console.WriteLine();
                }

                // We'll actually let linq do the heavy lifting.
                var sortedStats = from entry in stats.Values
                                  orderby entry.Size
                                  select entry;

                ulong totalSize = 0, totalCount = 0;
                Console.WriteLine("{0,12} {1,12} {2}", "Size", "Count", "Type");
                foreach (var entry in sortedStats)
                {
                    Console.WriteLine("{0,12:n0} {1,12:n0} {2}", entry.Size, entry.Count, entry.Name);
                    totalSize  += entry.Size;
                    totalCount += (uint)entry.Count;
                }

                Console.WriteLine();
                Console.WriteLine("Total: {0:n0} bytes in {1:n0} objects", totalSize, totalCount);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Unhandled exception:");
                Console.WriteLine(ex);
            }
        }
Example #18
0
        private static void DumpTypes(ClrHeap heap, ulong obj, string type)
        {
            var resultItem = new ServiceDescriptionEntry((int)heap.Runtime.DataTarget.ProcessId);

            // Get ServiceEndpoint[]
            List <ulong> endpointObjs = ClrMdHelper.GetLastObjectInHierarchyAsArray(heap, obj, HIERARCHY_ServiceDescription_To_ServiceEndpoints, 0, TYPE_ServiceEndpointArray);

            foreach (var endpointObj in endpointObjs)
            {
                var epEntry = new ServiceEndpointEntry();

                // Get Contract
                ulong  contractObj      = ClrMdHelper.GetLastObjectInHierarchy(heap, endpointObj, HIERARCHY_ServiceEndpoint_To_ContractType, 0);
                string contractTypeName = heap.GetObjectType(contractObj).GetRuntimeType(contractObj).Name;
                epEntry.Contract = contractTypeName;

                // Get IContractBehavior[]
                List <ulong> contractBehaviorObjs = ClrMdHelper.GetLastObjectInHierarchyAsArray(heap, endpointObj, HIERARCHY_ServiceEndpoint_To_ContractBehaviors, 0, TYPE_ContractBehaviorArray);

                foreach (var contractBehaviorObj in contractBehaviorObjs)
                {
                    ClrType itemType = heap.GetObjectType(contractBehaviorObj);
                    epEntry.ContractBehaviors.Add(itemType.Name);
                }

                // Get OperationDescription[]
                List <ulong> operationDescObjs = ClrMdHelper.GetLastObjectInHierarchyAsArray(heap, endpointObj, HIERARCHY_ServiceEndpoint_To_OperationDescriptions, 0, TYPE_OperationDescriptionArray);

                foreach (var operationDescObj in operationDescObjs)
                {
                    ulong  opNameObj = ClrMdHelper.GetLastObjectInHierarchy(heap, operationDescObj, HIERARCHY_OperationDescription_To_Name, 0);
                    string opName    = ClrMdHelper.GetObjectAs <string>(heap, opNameObj, FIELD_XmlName);
                    var    odEntry   = new OperationDescriptionEntry();
                    odEntry.OperationName = opName;

                    // Get IOperationBehavior[]
                    List <ulong> operationBehavObjs = ClrMdHelper.GetLastObjectInHierarchyAsArray(heap, operationDescObj, HIERARCHY_OperationDescription_To_OperationBehaviors, 0, TYPE_OperationBehaviorArray);

                    foreach (var operationBehavObj in operationBehavObjs)
                    {
                        ClrType itemType = heap.GetObjectType(operationBehavObj);
                        odEntry.OperationBehaviors.Add(itemType.Name);
                    }

                    epEntry.ContractOperations.Add(odEntry);
                }

                // Get CallbackContract
                ulong cbcontractObj = ClrMdHelper.GetLastObjectInHierarchy(heap, endpointObj, HIERARCHY_ServiceEndpoint_To_CallbackContractType, 0);

                if (cbcontractObj != 0)
                {
                    string cbcontractTypeName = heap.GetObjectType(cbcontractObj).GetRuntimeType(cbcontractObj).Name;
                    epEntry.CallbackContract = cbcontractTypeName;
                }

                // Get EndpointAddress URI
                ulong  uriObj = ClrMdHelper.GetLastObjectInHierarchy(heap, endpointObj, HIERARCHY_ServiceEndpoint_To_Uri, 0);
                string uri    = ClrMdHelper.GetObjectAs <string>(heap, uriObj, FIELD_UriName);
                epEntry.Uri = uri;

                // Get IEndpointBehavior[]
                List <ulong> endpBehaviorObjs = ClrMdHelper.GetLastObjectInHierarchyAsArray(heap, endpointObj, HIERARCHY_ServiceEndpoint_To_EndpointBehaviors, 0, TYPE_EndpointBehaviorArray);

                foreach (var endpBehaviorObj in endpBehaviorObjs)
                {
                    ClrType itemType = heap.GetObjectType(endpBehaviorObj);
                    epEntry.EndpointBehaviors.Add(itemType.Name);
                }

                resultItem.ServiceEndpoints.Add(epEntry);
            }

            // Get IServiceBehavior[]
            List <ulong> svcBehaviorObjs = ClrMdHelper.GetLastObjectInHierarchyAsArray(heap, obj, HIERARCHY_ServiceDescription_To_ServiceBehaviors, 0, TYPE_ServiceBehaviorArray);

            foreach (var svcBehaviorObj in svcBehaviorObjs)
            {
                ClrType svcBehaviorType = heap.GetObjectType(svcBehaviorObj);
                resultItem.ServiceBehaviors.Add(svcBehaviorType.Name);
            }

            RESULTS.Add(resultItem);
        }
Example #19
0
        public void Execute(CommandExecutionContext context)
        {
            if (!String.IsNullOrEmpty(TypeRegex))
            {
                try
                {
                    new Regex(TypeRegex);
                }
                catch (ArgumentException)
                {
                    context.WriteError("The regular expression specified for --type is not valid; did you forget to escape regex characters?");
                    return;
                }
            }

            _heap = context.Runtime.GetHeap();
            if (!_heap.CanWalkHeap)
            {
                context.WriteError("The heap is not in a walkable state.");
                return;
            }

            var  typeInfos        = new Dictionary <ulong, TypeInfo>(); // MT to TypeInfo
            long totalObjectCount = 0;

            if (!StatisticsOnly)
            {
                context.WriteLine("{0,-20} {1,-20} {2}", "MT", "Address", "Size");
            }
            foreach (var obj in _heap.EnumerateObjects())
            {
                ulong mt = 0;
                context.Runtime.ReadPointer(obj, out mt);

                if (!FilterObject(obj, mt))
                {
                    continue;
                }

                var type = _heap.GetObjectType(obj);
                if (type == null || String.IsNullOrEmpty(type.Name))
                {
                    continue;
                }

                var size = type.GetSize(obj);

                if (!StatisticsOnly)
                {
                    context.WriteLine("{0,-20:x16} {1,-20:x16} {2,-10}", mt, obj, size);
                }
                if (typeInfos.ContainsKey(mt))
                {
                    var current = typeInfos[mt];
                    current.Count += 1;
                    current.Size  += size;
                    typeInfos[mt]  = current;
                }
                else
                {
                    var objType     = _heap.GetObjectType(obj);
                    var objTypeName = objType != null ? objType.Name : "<no name>";
                    typeInfos.Add(mt, new TypeInfo {
                        Size = size, Count = 1, TypeName = objTypeName
                    });
                }
                ++totalObjectCount;
            }

            context.WriteLine("Statistics:");
            context.WriteLine("{0,-20} {1,-10} {2,-10} {3}", "MT", "Count", "TotalSize", "Class Name");
            foreach (var kvp in (from e in typeInfos orderby e.Value.Size ascending select e))
            {
                context.WriteLine("{0,-20:x16} {1,-10} {2,-10} {3}",
                                  kvp.Key, kvp.Value.Count, kvp.Value.Size, kvp.Value.TypeName);
            }
            context.WriteLine("Total {0} objects", totalObjectCount);
        }
Example #20
0
        public IEnumerable <TimerInfo> EnumerateTimers(ClrRuntime runtime)
        {
            ClrHeap heap = runtime.GetHeap();

            if (!heap.CanWalkHeap)
            {
                yield break;
            }

            var timerQueueType = GetMscorlib(runtime).GetTypeByName("System.Threading.TimerQueue");

            if (timerQueueType == null)
            {
                yield break;
            }

            ClrStaticField staticField = timerQueueType.GetStaticFieldByName("s_queue");

            if (staticField == null)
            {
                yield break;
            }

            foreach (ClrAppDomain domain in runtime.AppDomains)
            {
                ulong?timerQueue = (ulong?)staticField.GetValue(domain);
                if (!timerQueue.HasValue || timerQueue.Value == 0)
                {
                    continue;
                }

                // m_timers is the start of the list of TimerQueueTimer
                var currentPointer = 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 = GetFieldValue(heap, currentTimerQueueTimerRef, "m_dueTime");
                    ti.DueTime       = (uint)val;
                    val              = GetFieldValue(heap, currentTimerQueueTimerRef, "m_period");
                    ti.Period        = (uint)val;
                    val              = GetFieldValue(heap, currentTimerQueueTimerRef, "m_canceled");
                    ti.Cancelled     = (bool)val;
                    val              = 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 = 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 = BuildTimerCallbackMethodName(runtime, elementAddress);
                            }
                            else
                            {
                                ti.MethodName = "<" + elementType.Name + ">";
                            }
                        }
                        else
                        {
                            ti.MethodName = "{no callback type?}";
                        }
                    }
                    else
                    {
                        ti.MethodName = "???";
                    }

                    yield return(ti);

                    currentPointer = GetFieldValue(heap, currentTimerQueueTimerRef, "m_next");
                }
            }
        }
Example #21
0
    static void Main(string[] args)
    {
        if (!TryParseArgs(args, out string dump, out bool dso))
        {
            Usage();
            return;
        }

        // Create the data target.  This tells us the versions of CLR loaded in the target process.
        using DataTarget dataTarget = DataTarget.LoadDump(dump);

        // Now check bitness of our program/target:
        bool isTarget64Bit = dataTarget.DataReader.PointerSize == 8;

        if (Environment.Is64BitProcess != isTarget64Bit)
        {
            throw new Exception(string.Format("Architecture mismatch:  Process is {0} but target is {1}", Environment.Is64BitProcess ? "64 bit" : "32 bit", isTarget64Bit ? "64 bit" : "32 bit"));
        }

        // Note I just take the first version of CLR in the process.  You can loop over every loaded
        // CLR to handle the SxS case where both desktop CLR and .Net Core are loaded in the process.
        ClrInfo version = dataTarget.ClrVersions[0];

        // Now that we have the DataTarget, the version of CLR, and the right dac, we create and return a
        // ClrRuntime instance.
        using ClrRuntime runtime = version.CreateRuntime();

        // Walk each thread in the process.
        foreach (ClrThread thread in runtime.Threads)
        {
            // The ClrRuntime.Threads will also report threads which have recently died, but their
            // underlying datastructures have not yet been cleaned up.  This can potentially be
            // useful in debugging (!threads displays this information with XXX displayed for their
            // OS thread id).  You cannot walk the stack of these threads though, so we skip them
            // here.
            if (!thread.IsAlive)
            {
                continue;
            }

            Console.WriteLine("Thread {0:X}:", thread.OSThreadId);
            Console.WriteLine("Stack: {0:X} - {1:X}", thread.StackBase, thread.StackLimit);

            // Each thread tracks a "last thrown exception".  This is the exception object which
            // !threads prints.  If that exception object is present, we will display some basic
            // exception data here.  Note that you can get the stack trace of the exception with
            // ClrHeapException.StackTrace (we don't do that here).
            ClrException?currException = thread.CurrentException;
            if (currException is ClrException ex)
            {
                Console.WriteLine("Exception: {0:X} ({1}), HRESULT={2:X}", ex.Address, ex.Type.Name, ex.HResult);
            }

            // Walk the stack of the thread and print output similar to !ClrStack.
            Console.WriteLine();
            Console.WriteLine("Managed Callstack:");
            foreach (ClrStackFrame frame in thread.EnumerateStackTrace())
            {
                // Note that CLRStackFrame currently only has three pieces of data: stack pointer,
                // instruction pointer, and frame name (which comes from ToString).  Future
                // versions of this API will allow you to get the type/function/module of the
                // method (instead of just the name).  This is not yet implemented.
                Console.WriteLine($"    {frame.StackPointer:x12} {frame.InstructionPointer:x12} {frame}");
            }

            // Print a !DumpStackObjects equivalent.
            if (dso)
            {
                // We'll need heap data to find objects on the stack.
                ClrHeap heap = runtime.Heap;

                // Walk each pointer aligned address on the stack.  Note that StackBase/StackLimit
                // is exactly what they are in the TEB.  This means StackBase > StackLimit on AMD64.
                ulong start = thread.StackBase;
                ulong stop  = thread.StackLimit;

                // We'll walk these in pointer order.
                if (start > stop)
                {
                    ulong tmp = start;
                    start = stop;
                    stop  = tmp;
                }

                Console.WriteLine();
                Console.WriteLine("Stack objects:");

                // Walk each pointer aligned address.  Ptr is a stack address.
                for (ulong ptr = start; ptr <= stop; ptr += (uint)IntPtr.Size)
                {
                    // Read the value of this pointer.  If we fail to read the memory, break.  The
                    // stack region should be in the crash dump.
                    if (!dataTarget.DataReader.ReadPointer(ptr, out ulong obj))
                    {
                        break;
                    }

                    // 003DF2A4
                    // We check to see if this address is a valid object by simply calling
                    // GetObjectType.  If that returns null, it's not an object.
                    ClrType type = heap.GetObjectType(obj);
                    if (type == null)
                    {
                        continue;
                    }

                    // Don't print out free objects as there tends to be a lot of them on
                    // the stack.
                    if (!type.IsFree)
                    {
                        Console.WriteLine("{0,16:X} {1,16:X} {2}", ptr, obj, type.Name);
                    }
                }
            }

            Console.WriteLine();
            Console.WriteLine("----------------------------------");
            Console.WriteLine();
        }
    }
Example #22
0
        private IEnumerable<ulong> EnumerateManagedThreadpoolObjects()
        {
            m_heap = m_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 m_runtime.AppDomains)
                        {
                            ulong workQueue = (ulong)workQueueField.GetValue(appDomain);
                            ClrType workQueueType = m_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 m_runtime.AppDomains)
                        {
                            ulong threadQueue = (ulong)threadQueuesField.GetValue(domain);
                            if (threadQueue == 0)
                                continue;

                            ClrType threadQueueType = m_heap.GetObjectType(threadQueue);
                            if (threadQueueType == null)
                                continue;

                            ulong outerArray = 0;
                            ClrType outerArrayType = null;
                            if (!GetFieldObject(threadQueueType, threadQueue, "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 = m_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;
                                }
                            }
                        }
                    }
                }
            }
        }
Example #23
0
        internal override IList <ClrStackFrame> GetExceptionStackTrace(ulong obj, ClrType type)
        {
            // TODO: Review this and if it works on v4.5, merge the two implementations back into RuntimeBase.
            List <ClrStackFrame> result = new List <ClrStackFrame>();

            if (type == null)
            {
                return(result);
            }

            if (!GetStackTraceFromField(type, obj, out ulong _stackTrace))
            {
                if (!ReadPointer(obj + GetStackTraceOffset(), out _stackTrace))
                {
                    return(result);
                }
            }

            if (_stackTrace == 0)
            {
                return(result);
            }

            ClrHeap heap           = Heap;
            ClrType stackTraceType = heap.GetObjectType(_stackTrace);

            if (stackTraceType == null || !stackTraceType.IsArray)
            {
                return(result);
            }

            int len = stackTraceType.GetArrayLength(_stackTrace);

            if (len == 0)
            {
                return(result);
            }

            int   elementSize = IntPtr.Size * 4;
            ulong dataPtr     = _stackTrace + (ulong)(IntPtr.Size * 2);

            if (!ReadPointer(dataPtr, out ulong count))
            {
                return(result);
            }

            // Skip size and header
            dataPtr += (ulong)(IntPtr.Size * 2);

            DesktopThread thread = null;

            for (int i = 0; i < (int)count; ++i)
            {
                if (!ReadPointer(dataPtr, out ulong ip))
                {
                    break;
                }
                if (!ReadPointer(dataPtr + (ulong)IntPtr.Size, out ulong sp))
                {
                    break;
                }
                if (!ReadPointer(dataPtr + (ulong)(2 * IntPtr.Size), out ulong md))
                {
                    break;
                }

                if (i == 0 && sp != 0)
                {
                    thread = (DesktopThread)GetThreadByStackAddress(sp);
                }

                // it seems that the first frame often has 0 for IP and SP.  Try the 2nd frame as well
                if (i == 1 && thread == null && sp != 0)
                {
                    thread = (DesktopThread)GetThreadByStackAddress(sp);
                }

                result.Add(new DesktopStackFrame(this, thread, ip, sp, md));

                dataPtr += (ulong)elementSize;
            }

            return(result);
        }
Example #24
0
        private ClrType TryBuildType(ClrHeap heap)
        {
            var runtime = heap.GetRuntime();
            var domains = runtime.AppDomains;
            ClrType[] types = new ClrType[domains.Count];

            ClrElementType elType = ElementType;
            if (ClrRuntime.IsPrimitive(elType) || elType == ClrElementType.String)
                return ((DesktopGCHeap)heap).GetBasicType(elType);

            int count = 0;
            foreach (var domain in domains)
            {
                object value = GetValue(domain);
                if (value != null && value is ulong && ((ulong)value != 0))
                {
                    types[count++] = heap.GetObjectType((ulong)value);
                }
            }

            int depth = int.MaxValue;
            ClrType result = null;
            for (int i = 0; i < count; ++i)
            {
                ClrType curr = types[i];
                if (curr == result || curr == null)
                    continue;

                int nextDepth = GetDepth(curr);
                if (nextDepth < depth)
                {
                    result = curr;
                    depth = nextDepth;
                }
            }

            return result;
        }
Example #25
0
        // Returns all the info about any Composite Keys stored in memory
        public static List <CompositeKeyInfo> GetCompositeKeyInfo(Process process)
        {
            List <CompositeKeyInfo> keyInfo = new List <CompositeKeyInfo>();
            DataTarget dt = null;
            string     databaseLocation = "";

            try
            {
                dt = DataTarget.AttachToProcess(process.Id, 50000);

                if (dt.ClrVersions.Count == 0)
                {
                    string err = "CLR is not loaded. Is it Keepass 1.x, perhaps?";
                    Logger.WriteLine(err);
                    throw new Exception(err);
                }

                if (dt.ClrVersions.Count > 1)
                {
                    Logger.WriteLine("*** Interesting... there are multiple .NET runtimes loaded in KeePass");
                }

                ClrInfo    Version = dt.ClrVersions[0];
                ClrRuntime Runtime = Version.CreateRuntime();
                ClrHeap    Heap    = Runtime.GetHeap();

                if (!Heap.CanWalkHeap)
                {
                    string err = "Error: Cannot walk the heap!";
                    Logger.WriteLine(err);
                    throw new Exception(err);
                }

                foreach (ulong obj in Heap.EnumerateObjectAddresses())
                {
                    ClrType type = Heap.GetObjectType(obj);

                    if (type == null || type.Name != "KeePassLib.PwDatabase")
                    {
                        continue;
                    }

                    Logger.WriteLine("************ Found a PwDatabase! **********");

                    List <ulong> referencedObjects = ClrMDHelper.GetReferencedObjects(Heap, obj);

                    // First walk the referenced objects to find the database path
                    foreach (ulong refObj in referencedObjects)
                    {
                        ClrType refObjType = Heap.GetObjectType(refObj);
                        if (refObjType.Name == "KeePassLib.Serialization.IOConnectionInfo")
                        {
                            ClrInstanceField UrlField     = refObjType.GetFieldByName("m_strUrl");
                            ulong            UrlFieldAddr = UrlField.GetAddress(refObj);
                            object           Url          = UrlField.GetValue(UrlFieldAddr, true);
                            databaseLocation = (string)Url;
                        }
                    }

                    if (databaseLocation != "")
                    {
                        Logger.WriteLine("*** PwDatabase location : " + databaseLocation);

                        referencedObjects = ClrMDHelper.GetReferencedObjects(Heap, obj);

                        // now walk the referenced objects looking for a master composite key
                        foreach (ulong refObj in referencedObjects)
                        {
                            ClrType refObjType = Heap.GetObjectType(refObj);
                            if (refObjType.Name == "KeePassLib.Keys.CompositeKey")
                            {
                                Logger.WriteLine("************ Found a CompositeKey! **********");
                                CompositeKeyInfo CompositeKey = new CompositeKeyInfo();

                                // Get all objects kept alive by the composite key.
                                // (A shortcut to get references to all Key types)
                                List <ulong> referencedObjects2 = ClrMDHelper.GetReferencedObjects(Heap, refObj);

                                foreach (ulong refObj2 in referencedObjects2)
                                {
                                    ClrType refObjType2 = Heap.GetObjectType(refObj2);

                                    if (refObjType2.Name == "KeePassLib.Keys.KcpPassword")
                                    {
                                        KcpPassword KcpPassword = GetKcpPasswordInfo(refObj2, refObjType2, Heap, databaseLocation);

                                        if (KcpPassword == null)
                                        {
                                            continue;
                                        }

                                        CompositeKey.AddUserKey(KcpPassword);
                                    }
                                    else if (refObjType2.Name == "KeePassLib.Keys.KcpKeyFile")
                                    {
                                        KcpKeyFile KcpKeyFile = GetKcpKeyFileInfo(refObj2, refObjType2, Heap, databaseLocation);

                                        if (KcpKeyFile == null)
                                        {
                                            continue;
                                        }

                                        CompositeKey.AddUserKey(KcpKeyFile);
                                    }
                                    else if (refObjType2.Name == "KeePassLib.Keys.KcpUserAccount")
                                    {
                                        KcpUserAccount KcpUserAccount = GetKcpUserAccountInfo(refObj2, refObjType2, Heap, databaseLocation);

                                        if (KcpUserAccount == null)
                                        {
                                            continue;
                                        }

                                        CompositeKey.AddUserKey(KcpUserAccount);
                                    }
                                }
                                if (CompositeKey.UserKeyCount > 0)
                                {
                                    keyInfo.Add(CompositeKey);
                                }
                            }
                        }
                    }
                }

                Logger.Write("\n");
            }
            catch (Exception e)
            {
                Logger.WriteLine(e.Message);
                throw;
            }
            finally
            {
                if (dt != null)
                {
                    dt.Dispose();
                }
            }

            return(keyInfo);
        }