Beispiel #1
0
        public void Execute(CommandExecutionContext context)
        {
            _context = context;

            if (!CommandHelpers.VerifyValidObjectAddress(context, ObjectAddress))
                return;

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

            var type = _heap.GetObjectType(ObjectAddress);

            _visitedObjects = new ObjectSet(_heap);
            _targets[ObjectAddress] = new Node(ObjectAddress, type);
            FillRootDictionary();

            foreach (var root in _roots)
            {
                if (_visitedRoots.Contains(root) || _visitedObjects.Contains(root.Object))
                    continue;

                Node path = TryFindPathToTarget(root);
                if (path != null)
                    PrintOnePath(path);
            }
        }
        // Returns all objects being kept alive by the input object
        // Based off the code at https://github.com/Microsoft/clrmd/blob/master/Documentation/WalkingTheHeap.md
        public static List<ulong> GetReferencedObjects(ClrHeap heap, ulong obj)
        {
            List<ulong> references = new List<ulong>();
            Stack<ulong> eval = new Stack<ulong>();

            HashSet<ulong> considered = new HashSet<ulong>();

            eval.Push(obj);

            while (eval.Count > 0)
            {
                obj = eval.Pop();
                if (considered.Contains(obj))
                    continue;

                considered.Add(obj);

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

                references.Add(obj);

                // Now enumerate all objects that this object points to, add them to the
                // evaluation stack if we haven't seen them before.
                type.EnumerateRefsOfObjectCarefully(obj, delegate (ulong child, int offset)
                {
                    if (child != 0 && !considered.Contains(child))
                        eval.Push(child);
                });
            }

            return references;
        }
Beispiel #3
0
        public ClrObject(ClrHeap heap, ClrType type, ulong addr, bool inner)
        {
            if (heap == null)
                throw new ArgumentNullException("heap");

            m_addr = addr;
            m_inner = inner;
            m_heap = heap;

            // For interior pointers (structs inside other objects), we simply have to trust the caller
            // gave us the right thing.
            m_type = inner ? type : heap.GetObjectType(addr);
        }
			public static MultiElementDictionary2<ulong> Build(ClrHeap heap)
			{

				var result = new MultiElementDictionary2<ulong>();

				foreach (var objRef in heap.EnumerateObjects())
				{
					var type = heap.GetObjectType(objRef);
					result.Add(type.Name, objRef);
				}

				return result;
			}
Beispiel #5
0
    static object Format(ClrHeap heap, object val)
    {
        if (val == null)
            return "{null}";

        if (val is ulong)
        {
            ulong addr = (ulong)val;
            var type = heap.GetObjectType(addr);
            if (type != null && type.Name == "System.String")
                return type.GetValue(addr);
            else
                return ((ulong)val).ToString("X");
        }

        return val;
    }
Beispiel #6
0
        public ClrObject(ClrHeap heap, ClrType type, ulong addr)
        {
            if (heap == null)
                throw new ArgumentNullException("heap");

            m_addr = addr;
            m_heap = heap;

            if (addr != 0)
            {
                var gcType = heap.GetObjectType(addr);
                if (gcType != null)
                    type = gcType;
            }

            m_type = type;
        }
        private void GetObjSize(ClrHeap heap, ulong obj, out uint count, out ulong size)
        {
            // Evaluation stack
            var eval = new Stack<ulong>();

            // To make sure we don't count the same object twice, we'll keep a set of all objects
            // we've seen before.
            var considered = new HashSet<ulong>();

            count = 0;
            size = 0;
            eval.Push(obj);

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

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

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

                // Now enumerate all objects that this object points to, add them to the
                // evaluation stack if we haven't seen them before.
                type.EnumerateRefsOfObject(obj, (child, offset) =>
                {
                    if (child != 0 && !considered.Contains(child))
                        eval.Push(child);
                });
            }
        }
 public async Task<IEnumerable<object>> Execute(Models.OperationModel model, CancellationToken token, object customeParameter)
 {
     return await DebuggerSession.Instance.ExecuteOperation(() =>
     {
         _token = token;
         _heap = DebuggerSession.Instance.Runtime.GetHeap();
         _found = false;
         var stack = new Stack<ulong>();
         foreach (var root in _heap.EnumerateRoots())
         {
             stack.Clear();
             stack.Push(root.Object);
             if (token.IsCancellationRequested)
                 break;
             GetRefChainFromRootToObject(model.ObjectAddress, stack, new HashSet<ulong>());
             if (_found) break;
         }
         var enumerable = from address in stack
                          orderby address ascending
                          let type = _heap.GetObjectType(address)
                          select new { Address = address, Type = type.Name, MetadataToken = type.MetadataToken, };
         return enumerable.ToList();
     });
 }
Beispiel #9
0
        private static IEnumerable<Tuple<ulong, ClrType>> EnumerateFromObjectSet(ClrHeap heap, IEnumerable<ulong> objects)
        {
            var toGoThrough = new Stack<ulong>(objects);
            var seen = new ObjectSet(heap);

            while (toGoThrough.Count > 0)
            {
                var obj = toGoThrough.Pop();
                if (seen.Contains(obj))
                    continue;

                seen.Add(obj);

                var type = heap.GetObjectType(obj);
                if (type == null || type.IsFree || String.IsNullOrEmpty(type.Name))
                    continue;

                yield return new Tuple<ulong, ClrType>(obj, type);

                type.EnumerateRefsOfObject(obj, (child, _) =>
                {
                    if (child != 0 && !seen.Contains(child))
                    {
                        toGoThrough.Push(child);
                    }
                });
            }
        }
Beispiel #10
0
        private 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;
        }
Beispiel #11
0
        public void Execute(CommandExecutionContext context)
        {
            if (!String.IsNullOrEmpty(TypeRegex))
            {
                try
                {
                    new Regex(TypeRegex);
                }
                catch (ArgumentException)
                {
                    context.WriteErrorLine("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.WriteErrorLine("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.EnumerateObjectAddresses())
            {
                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);
        }
        private static void ExamineProcessHeap(ClrRuntime runtime, ClrHeap heap, bool showGcHeapInfo)
        {            
            if (!heap.CanWalkHeap)
            {
                Console.WriteLine("Cannot walk the heap!");
                return;
            }

            ulong totalStringObjectSize = 0, stringObjectCounter = 0, byteArraySize = 0;
            ulong asciiStringSize = 0, unicodeStringSize = 0, isoStringSize = 0; //, utf8StringSize = 0;
            ulong asciiStringCount = 0, unicodeStringCount = 0, isoStringCount = 0; //, utf8StringCount = 0;
            ulong compressedStringSize = 0, uncompressedStringSize = 0;
            foreach (var obj in heap.EnumerateObjectAddresses())
            {
                ClrType type = heap.GetObjectType(obj);
                // If heap corruption, continue past this object. Or if it's NOT a String we also ignore it
                if (type == null || type.IsString == false)
                    continue;

                stringObjectCounter++;
                var text = (string)type.GetValue(obj);
                var rawBytes = Encoding.Unicode.GetBytes(text);
                totalStringObjectSize += type.GetSize(obj);
                byteArraySize += (ulong)rawBytes.Length;

                VerifyStringObjectSize(runtime, type, obj, text);

                // Try each encoding in order, so we find the most-compact encoding that the text would fit in
                byte[] textAsBytes = null;
                if (IsASCII(text, out textAsBytes))
                {
                    asciiStringSize += (ulong)rawBytes.Length;
                    asciiStringCount++;

                    // ASCII is compressed as ISO-8859-1 (Latin-1) NOT ASCII
                    if (IsIsoLatin1(text, out textAsBytes))
                        compressedStringSize += (ulong)textAsBytes.Length;
                    else
                        Console.WriteLine("ERROR: \"{0}\" is ASCII but can't be encoded as ISO-8859-1 (Latin-1)", text);
                }
                // From http://stackoverflow.com/questions/7048745/what-is-the-difference-between-utf-8-and-iso-8859-1
                // "ISO 8859-1 is a single-byte encoding that can represent the first 256 Unicode characters"
                else if (IsIsoLatin1(text, out textAsBytes))
                {
                    isoStringSize += (ulong)rawBytes.Length;
                    isoStringCount++;
                    compressedStringSize += (ulong)textAsBytes.Length;
                }
                // UTF-8 and UTF-16 can both support the same range of text/character values ("Code Points"), they just store it in different ways
                // From http://stackoverflow.com/questions/4655250/difference-between-utf-8-and-utf-16/4655335#4655335
                // "Both UTF-8 and UTF-16 are variable length (multi-byte) encodings.
                // However, in UTF-8 a character may occupy a minimum of 8 bits, while in UTF-16 character length starts with 16 bits."
                //else if (IsUTF8(text, out textAsBytes))
                //{
                //    utf8StringSize += (ulong)rawBytes.Length;
                //    utf8StringCount++;
                //    compressedStringSize += (ulong)textAsBytes.Length;
                //}
                else
                {
                    unicodeStringSize += (ulong)rawBytes.Length;
                    unicodeStringCount++;
                    uncompressedStringSize += (ulong)rawBytes.Length;
                }
            }

            Console.ForegroundColor = ConsoleColor.DarkYellow;
            Console.WriteLine("\n\"System.String\" memory usage info");
            Console.ResetColor();
            Console.WriteLine("Overall {0:N0} \"System.String\" objects take up {1:N0} bytes ({2:N2} MB)",
                                stringObjectCounter, totalStringObjectSize, totalStringObjectSize / 1024.0 / 1024.0);
            Console.WriteLine("Of this underlying byte arrays (as Unicode) take up {0:N0} bytes ({1:N2} MB)",
                                byteArraySize, byteArraySize / 1024.0 / 1024.0);
            Console.WriteLine("Remaining data (object headers, other fields, etc) are {0:N0} bytes ({1:N2} MB), at {2:0.##} bytes per object\n",
                                totalStringObjectSize - byteArraySize,
                                (totalStringObjectSize - byteArraySize) / 1024.0 / 1024.0,
                                (totalStringObjectSize - byteArraySize) / (double)stringObjectCounter);

            Console.ForegroundColor = ConsoleColor.DarkYellow;
            Console.WriteLine("Actual Encoding that the \"System.String\" could be stored as (with corresponding data size)");
            Console.ResetColor();
            Console.WriteLine("  {0,15:N0} bytes ({1,8:N0} strings) as ASCII", asciiStringSize, asciiStringCount);
            Console.WriteLine("  {0,15:N0} bytes ({1,8:N0} strings) as ISO-8859-1 (Latin-1)", isoStringSize, isoStringCount);
            //Console.WriteLine("  {0,15:N0} bytes ({1,8:N0} strings) are UTF-8", utf8StringSize, utf8StringCount);
            Console.WriteLine("  {0,15:N0} bytes ({1,8:N0} strings) as Unicode", unicodeStringSize, unicodeStringCount);
            Console.WriteLine("Total: {0:N0} bytes (expected: {1:N0}{2})\n",
                                asciiStringSize + isoStringSize + unicodeStringSize, byteArraySize,
                                (asciiStringSize + isoStringSize + unicodeStringSize != byteArraySize) ? " - ERROR" : "");

            Console.ForegroundColor = ConsoleColor.DarkYellow;
            Console.WriteLine("Compression Summary:");
            Console.ResetColor();
            Console.WriteLine("  {0,15:N0} bytes Compressed (to ISO-8859-1 (Latin-1))", compressedStringSize);
            Console.WriteLine("  {0,15:N0} bytes Uncompressed (as Unicode)", uncompressedStringSize);
            Console.WriteLine("  {0,15:N0} bytes EXTRA to enable compression (1-byte field, per \"System.String\" object)", stringObjectCounter);
            var totalBytesUsed = compressedStringSize + uncompressedStringSize + stringObjectCounter;
            var totalBytesSaved = byteArraySize - totalBytesUsed;
            Console.WriteLine("\nTotal Usage:  {0:N0} bytes ({1:N2} MB), compared to {2:N0} ({3:N2} MB) before compression",
                                totalBytesUsed, totalBytesUsed / 1024.0 / 1024.0,
                                byteArraySize, byteArraySize / 1024.0 / 1024.0);
            Console.WriteLine("Total Saving: {0:N0} bytes ({1:N2} MB)\n", totalBytesSaved, totalBytesSaved / 1024.0 / 1024.0);            
        }
Beispiel #13
0
        private static ObjectSet GetLiveObjects(ClrHeap heap)
        {
            ObjectSet considered = new ObjectSet(heap);
            Stack<ulong> eval = new Stack<ulong>();

            foreach (var root in heap.EnumerateRoots())
                eval.Push(root.Object);

            while (eval.Count > 0)
            {
                ulong obj = eval.Pop();
                if (considered.Contains(obj))
                    continue;

                considered.Add(obj);

                var type = heap.GetObjectType(obj);
                if (type == null)  // Only if heap corruption
                    continue;

                type.EnumerateRefsOfObject(obj, delegate(ulong child, int offset)
                {
                    if (child != 0 && !considered.Contains(child))
                        eval.Push(child);
                });
            }

            return considered;
        }
Beispiel #14
0
        internal ClrHandle(Microsoft.Diagnostics.Runtime.Desktop.V45Runtime clr, ClrHeap heap, Microsoft.Diagnostics.Runtime.Desktop.HandleData handleData)
        {
            Address obj;
            Address = handleData.Handle;
            clr.ReadPointer(Address, out obj);

            Object = obj;
            Type = heap.GetObjectType(obj);

            uint refCount = 0;

            if (handleData.Type == (int)HandleType.RefCount)
            {
                if (handleData.IsPegged != 0)
                    refCount = handleData.JupiterRefCount;

                if (refCount < handleData.RefCount)
                    refCount = handleData.RefCount;

                if (Type != null)
                {
                    if (Type.IsCCW(obj))
                    {
                        CcwData data = Type.GetCCWData(obj);
                        if (data != null && refCount < data.RefCount)
                            refCount = (uint)data.RefCount;
                    }
                    else if (Type.IsRCW(obj))
                    {
                        RcwData data = Type.GetRCWData(obj);
                        if (data != null && refCount < data.RefCount)
                            refCount = (uint)data.RefCount;
                    }
                }

                RefCount = refCount;
            }


            HandleType = (HandleType)handleData.Type;
            AppDomain = clr.GetAppDomainByAddress(handleData.AppDomain);

            if (HandleType == HandleType.Dependent)
            {
                DependentTarget = handleData.Secondary;
                DependentType = heap.GetObjectType(handleData.Secondary);
            }
        }
Beispiel #15
0
        public static KcpUserAccount GetKcpUserAccountInfo(ulong KcpUserAccountAddr, ClrType KcpUserAccountType, ClrHeap Heap, string databaseLocation)
        {
            KcpUserAccount UserAccountInfo = new KcpUserAccount();

            // Get the embedded ProtectedBinary
            ClrInstanceField KcpProtectedBinaryField = KcpUserAccountType.GetFieldByName("m_pbKeyData");
            ulong KcpProtectedBinaryAddr = KcpProtectedBinaryField.GetAddress(KcpUserAccountAddr);
            ulong KcpProtectedBinaryObjAddr = (ulong)KcpProtectedBinaryField.GetValue(KcpUserAccountAddr);

            ClrInstanceField EncDataField = KcpProtectedBinaryField.Type.GetFieldByName("m_pbData");
            ulong EncDataAddr = EncDataField.GetAddress(KcpProtectedBinaryObjAddr);
            ulong EncDataArrayAddr = (ulong)EncDataField.GetValue(KcpProtectedBinaryObjAddr);

            ClrType EncDataArrayType = Heap.GetObjectType(EncDataArrayAddr);
            int len = EncDataField.Type.GetArrayLength(EncDataArrayAddr);

            if (len <= 0 || len % 16 != 0) // Small sanity check to make sure everything's ok
                return null;

            byte[] EncData = new byte[len];
            for (int i = 0; i < len; i++)
            {
                EncData[i] = (byte)EncDataArrayType.GetArrayElementValue(EncDataArrayAddr, i);
            }

            UserAccountInfo.databaseLocation = databaseLocation;
            UserAccountInfo.encryptedBlob = EncData;
            UserAccountInfo.encryptedBlobAddress = (IntPtr)KcpUserAccountType.GetArrayElementAddress(EncDataArrayAddr, 0);
            UserAccountInfo.encryptedBlobLen = len;

            return UserAccountInfo;
        }