Beispiel #1
0
        public static object GetSimpleValue(ulong objAddress, ClrType clrType, bool isInterior = false)
        {
            if (objAddress == 0)
            {
                throw new NullReferenceException("ClrObject at is pointing to null address.");
            }

            ClrHeap heap = clrType.Heap;

            if (clrType.IsEnum)
            {
                var val = clrType.GetValue(objAddress);
                return(clrType.GetEnumName(val));
            }

            if (clrType.IsPrimitive || clrType.IsString)
            {
                return(clrType.GetValue(objAddress));
            }

            ulong address = isInterior ? objAddress : objAddress + (ulong)heap.PointerSize;

            switch (clrType.Name)
            {
            case GuidTypeName:
            {
                byte[] buffer = ReadBuffer(heap, address, 16);
                return(new Guid(buffer));
            }

            case TimeSpanTypeName:
            {
                byte[] buffer = ReadBuffer(heap, address, 8);
                long   ticks  = BitConverter.ToInt64(buffer, 0);
                return(new TimeSpan(ticks));
            }

            case DateTimeTypeName:
            {
                byte[] buffer   = ReadBuffer(heap, address, 8);
                ulong  dateData = BitConverter.ToUInt64(buffer, 0);
                return(GetDateTime(dateData));
            }

            case IPAddressTypeName:
            {
                return(GetIPAddress(new ClrObject(objAddress, clrType, isInterior)));
            }
            }

            throw new InvalidOperationException(string.Format("SimpleValue not available for type '{0}'", clrType.Name));
        }
Beispiel #2
0
        public override string ToString()
        {
            if (IsNull())
            {
                return("<null>");
            }

            if (m_type.IsString)
            {
                return(m_type.GetValue(m_addr).ToString());
            }

            return(string.Format(@"[{0:x16} {1}]", m_addr, m_type.Name));
        }
Beispiel #3
0
        public override bool TryConvert(ConvertBinder binder, out object result)
        {
            if (m_type == null)
            {
                return(ClrNullValue.GetDefaultNullValue(binder.Type, out result));
            }

            if (binder.Type == typeof(ClrType))
            {
                // Special case:  The caller is requesting the GCHeapType of what we are inspecting.
                result = m_type;
                return(true);
            }

            if (binder.Type.IsPrimitive && m_type.IsPrimitive && m_type.HasSimpleValue)
            {
                result = Convert.ChangeType(m_type.GetValue(m_addr), binder.Type);
                return(true);
            }

            if (binder.Type == typeof(ulong))
            {
                result = m_addr;
                return(true);
            }

            if (binder.Type == typeof(long))
            {
                result = (long)m_addr;
                return(true);
            }

            if (binder.Type == typeof(string))
            {
                if (m_type.IsString)
                {
                    result = m_type.GetValue(m_addr);
                }
                else
                {
                    result = ToString();
                }
                return(true);
            }


            result = null;
            return(false);
        }
Beispiel #4
0
 public static object GetPrimitiveValueNonBoxed(this ClrType type, ulong address)
 {
     // The ClrType.GetValue implementation assumes that if a primitive
     // is passed in, then it must be boxed, and adds 4/8 bytes to the address
     // specified. We compensate by subtracting 4/8 bytes as necessary.
     return(type.GetValue(address - (ulong)IntPtr.Size));
 }
Beispiel #5
0
        public object Read()
        {
            ulong address = Address;

            // This is required due to a bug in Microsoft.Diagnostics.Runtime
            if (Type.IsPrimitive)
            {
                address -= (ulong)((long)this.Heap.PointerSize);
            }

            return(Type.GetValue(address));
        }
        public static void AddSimpleValueColumn(this ObjectListView listView, Func <object, ulong> addressGetter, ClrDump dump, Func <object, ClrType> typeGetter)
        {
            var col = new OLVColumn("Value", null)
            {
                Width = 150
            };

            col.AspectGetter = o =>
            {
                ClrType type    = typeGetter(o);
                ulong   address = addressGetter(o);
                object  result  = dump.Eval(
                    () => {
                    if (type.IsPrimitive || type.IsString)
                    {
                        return(type.GetValue(address));
                    }
                    return(address);
                }
                    );
                return(result);
            };
            listView.AllColumns.Add(col);
            var menuItem = new ToolStripMenuItem("Copy Value");

            listView.ContextMenuStrip.Items.Add(menuItem);
            menuItem.Click += (o, e) =>
            {
                if (listView.SelectedItem == null)
                {
                    return;
                }

                int    index       = listView.SelectedItem.Index;
                var    modelObject = listView.GetModelObject(index);
                string val         = col.GetStringValue(modelObject);
                string escapeVal   = StringHelpers.Escape(val);
                if (string.IsNullOrEmpty(escapeVal))
                {
                    Clipboard.SetText("null");
                }
                else
                {
                    Clipboard.SetText(escapeVal);
                }
            };
        }
            public static object GetSimpleValue(ClrObject obj)
            {
                if (obj.IsNull())
                {
                    return(null);
                }

                ClrType type = obj.Type;
                ClrHeap heap = type.Heap;

                if (type.IsPrimitive || type.IsString)
                {
                    return(type.GetValue(obj.Address));
                }

                ulong address = obj.IsInterior ? obj.Address : obj.Address + (ulong)heap.PointerSize;

                switch (type.Name)
                {
                case GuidTypeName:
                {
                    byte[] buffer = ReadBuffer(heap, address, 16);
                    return(new Guid(buffer));
                }

                case TimeSpanTypeName:
                {
                    byte[] buffer = ReadBuffer(heap, address, 8);
                    long   ticks  = BitConverter.ToInt64(buffer, 0);
                    return(new TimeSpan(ticks));
                }

                case DateTimeTypeName:
                {
                    byte[] buffer   = ReadBuffer(heap, address, 8);
                    ulong  dateData = BitConverter.ToUInt64(buffer, 0);
                    return(GetDateTime(dateData));
                }

                case IPAddressTypeName:
                {
                    return(GetIPAddress(obj));
                }
                }

                throw new InvalidOperationException(string.Format("SimpleValue not available for type '{0}'", type.Name));
            }
Beispiel #8
0
 private IClrObject ReadFromNotNullAddress(ClrType type, ulong address)
 {
     if (type.IsArray)
     {
         return(new ClrArrayObject(type, address));
     }
     if (type.IsValueClass)
     {
         return(new ClrStructObject(null, type, address));
     }
     if (type.IsPrimitive || type.IsString)
     {
         var value = type.GetValue(address);
         return(WrapPrimitiveValue(type, value));
     }
     return(new ClrClassObject(type, address));
 }
            public string ValueRaw()
            {
                if (ClrType != null)
                {
                    // NOTE ObjectAddress could be 0 while the value is simply unavailable.

                    // Display strings inline.
                    if (ClrType.IsString && Value != null)
                    {
                        return(ClrType.GetValue(ObjectAddress).ToStringOrNull());
                    }

                    // Display objects (non-strings) as an address.
                    if (ClrType.IsObjectReference && Value != null)
                    {
                        return(String.Format("{0:x16}", ObjectAddress));
                    }

                    if (HasNonTrivialValueToDisplay)
                    {
                        return("VALTYPE");
                    }

                    // Display primitive value types inline.
                    if (ClrType.HasSimpleValue && Location != 0)
                    {
                        return(ClrType.GetPrimitiveValueNonBoxed(Location).ToStringOrNull());
                    }
                }

                if (Value == null || Value.Length == 0)
                {
                    return("<unavailable>");
                }

                StringBuilder result = new StringBuilder();

                foreach (byte b in Value)
                {
                    result.AppendFormat("{0:x2} ", b);
                }
                return(result.ToString());
            }
Beispiel #10
0
        static (int length, string text) ReadString(ClrType type, ulong obj)
        {
            ClrInstanceField lengthField = type.GetFieldByName("_stringLength");

            if (lengthField == null)
            {
                return(0, String.Empty);
            }

            var stringLength = (int)lengthField.GetValue(obj);

            if (stringLength <= 0)
            {
                return(stringLength, String.Empty);
            }

            var text = (string)type.GetValue(obj);

            return(stringLength, text);
        }
Beispiel #11
0
        public static long GetEnumValue(ulong addr, ClrType clrType, ClrElementType enumElem)
        {
            object enumVal = clrType.GetValue(addr);

            if (enumVal is int)
            {
                return((long)(int)enumVal);
            }
            else
            {
                // The approved types for an enum are byte, sbyte, short, ushort, int, uint, long, or ulong.
                switch (enumElem)
                {
                case ClrElementType.UInt32:
                    return((long)((uint)enumVal));

                case ClrElementType.UInt8:
                    return((long)(byte)enumVal);

                case ClrElementType.Int8:
                    return((long)(sbyte)enumVal);

                case ClrElementType.Int16:
                    return((long)(short)enumVal);

                case ClrElementType.UInt16:
                    return((long)(ushort)enumVal);

                case ClrElementType.Int64:
                    return((long)enumVal);

                case ClrElementType.UInt64:
                    return((long)(ulong)enumVal);

                default:
                    return(EnumValues.InvalidEnumValue);
                }
            }
        }
Beispiel #12
0
        static void ReadEnum(ClrType type, ulong obj)
        {
            int objValue = (int)type.GetValue(obj);

            bool found = false;

            foreach (var name in type.GetEnumNames())
            {
                int value;
                if (type.TryGetEnumValue(name, out value) && objValue == value)
                {
                    Console.WriteLine("{0} - {1}", value, name);
                    found = true;
                    break;
                }
            }

            if (!found)
            {
                Console.WriteLine("{0} - {1}", objValue, "Unknown");
            }
        }
Beispiel #13
0
        public void IntegerObjectClrType()
        {
            using (DataTarget dt = TestTargets.Types.LoadFullDump())
            {
                ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime();
                ClrHeap    heap    = runtime.Heap;

                ClrStaticField field = runtime.GetModule("types.exe").GetTypeByName("Types").GetStaticFieldByName("s_i");

                ulong   addr = (ulong)field.GetValue(runtime.AppDomains.Single());
                ClrType type = heap.GetObjectType(addr);
                Assert.True(type.IsPrimitive);
                Assert.False(type.IsObjectReference);
                Assert.False(type.IsValueClass);

                object value = type.GetValue(addr);
                Assert.Equal("42", value.ToString());
                Assert.IsType <int>(value);
                Assert.Equal(42, (int)value);

                Assert.Contains(addr, heap.EnumerateObjectAddresses());
            }
        }
        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 #15
0
 public override object GetValue(Address objRef, bool interior)
 {
     return(Type.GetValue(GetAddress(objRef, interior)));
 }
Beispiel #16
0
        private List <ClrObjectModel> GetValues(ulong obj, ClrType type, string baseName, int offset, bool inner, List <ClrObjectModel> values)
        {
            if (type.Name == "System.String")
            {
                object value;
                try
                {
                    value = type.GetValue(obj);
                }
                catch (Exception ex)
                {
                    value = ex.Message;
                }
                values.Add(new ClrObjectModel {
                    Address = obj, BaseName = baseName, TypeName = type.Name, Value = value
                });
                values.AddRange(type.Fields.Select(field => new ClrObjectModel {
                    Address = obj, BaseName = baseName, FieldName = field.Name, Offset = field.Offset + offset, TypeName = field.Type.Name, Value = field.GetValue(obj, inner).ToString()
                }));
            }
            else if (type.IsArray)
            {
                int len = type.GetArrayLength(obj);

                if (type.ComponentType == null)
                {
                    try
                    {
                        for (int i = 0; i < len; i++)
                        {
                            values.Add(new ClrObjectModel {
                                Address = obj, BaseName = baseName, TypeName = type.Name, Value = type.GetArrayElementValue(obj, i)
                            });
                        }
                    }
                    catch { }
                }
                else if (type.ComponentType.HasSimpleValue)
                {
                    for (int i = 0; i < len; i++)
                    {
                        values.Add(new ClrObjectModel {
                            Address = obj, BaseName = baseName, TypeName = type.Name, Value = type.GetArrayElementValue(obj, i)
                        });
                    }
                }
                else
                {
                    for (int i = 0; i < len; i++)
                    {
                        ulong arrAddress = type.GetArrayElementAddress(obj, i);

                        foreach (var field in type.ComponentType.Fields)
                        {
                            string value;
                            if (field.HasSimpleValue)
                            {
                                value = field.GetValue(arrAddress, inner).ToString();   // an embedded struct
                            }
                            else
                            {
                                value = field.GetAddress(arrAddress, inner).ToString();
                            }

                            values.Add(new ClrObjectModel {
                                Address = obj, BaseName = baseName, FieldName = field.Name, Offset = field.Offset + offset, TypeName = field.Type.Name, Value = value
                            });

                            if (field.ElementType == ClrElementType.Struct)
                            {
                                values.AddRange(GetValues(arrAddress, field.Type, baseName + field.Name, offset + field.Offset, true, new List <ClrObjectModel>()));
                            }
                        }
                    }
                }
            }
            else
            {
                foreach (var field in type.Fields)
                {
                    ulong addr = field.GetAddress(obj, inner);

                    object value;
                    if (field.HasSimpleValue)
                    {
                        try
                        {
                            value = field.GetValue(obj, inner);
                        }
                        catch (Exception)
                        {
                            value = "{Unknown}";
                        }
                    }
                    else
                    {
                        value = addr;
                    }

                    string sValue = value?.ToString() ?? "{Null}";
                    values.Add(new ClrObjectModel {
                        Address = obj, BaseName = baseName, FieldName = field.Name, Offset = field.Offset + offset, TypeName = field.Type.Name, Value = sValue
                    });

                    if (field.ElementType == ClrElementType.Struct)
                    {
                        values.AddRange(GetValues(addr, field.Type, baseName + field.Name, offset + field.Offset, true, new List <ClrObjectModel>()));
                    }
                }
            }

            return(values);
        }
Beispiel #17
0
        private void DumpFields(ulong Address, ClrType type = null)
        {
            StartRuntime();
            ClrType obj;

            if (type == null)
            {
                obj = m_heap.GetObjectType(Address);
            }
            else
            {
                obj = type;
            }

            if (cache == null)
            {
                cache = new HeapCache(m_runtime, ShowProgress);
            }
            MDType      tp = new MDType(obj);
            MD_TypeData data;

            tp.GetHeader(Address, out data);
            int count = 0;

            tp.GetAllFieldsDataRawCount(out count);
            int temp = 0;

            MD_FieldData[] fields = new MD_FieldData[count];

            tp.GetAllFieldsDataRaw(data.isValueType ? 1 : 0, count, fields, out temp);

            for (int i = 0; i < count; i++)
            {
                string typeName;
                string Name;
                tp.GetRawFieldTypeAndName(i, out typeName, out Name);
                MD_TypeData fd;
                ClrType     ftp     = AdHoc.GetTypeFromMT(m_runtime, fields[i].MethodTable);
                MDType      ft      = new MDType(ftp);
                ulong       pointer = 0;

                tp.GetRawFieldAddress(Address, data.isValueType ? 1 : 0, i, out pointer);
                if (fields[i].isValueType)
                {
                    ft.GetHeader(pointer, out fd);
                }
                else
                {
                    ft.GetHeader(ReadPointer(pointer), out fd);
                }
                Write("{0:x16} {1:x4} {5:x16} {6} +{2:x4} {3,30} {4,30} {7} ", fd.module,
                      fd.token, fields[i].offset, TrimRight(typeName, 30), Name,
                      data.MethodTable, fields[i].isThreadStatic ? " thread " : fields[i].isStatic ? " Static " : "        ",
                      fields[i].isEnum  ?
                      AdHoc.GetEnumName(ftp,
                                        ReadPointer(pointer) & (fd.size == 4 ?
                                                                0x0000FFFF : ulong.MaxValue))
                    : "" /*cache.GetFieldValue(Address, Name, obj)*/);
                ulong effAddress = pointer;
                if (fd.isValueType)
                {
                    if (fields[i].isEnum)
                    {
                        WriteLine("");
                        continue;
                    }

                    try
                    {
                        WriteLine("{0}", ftp.GetValue(pointer));
                    }
                    catch
                    {
                        WriteLine("{0}", ReadPointer(pointer) & (fd.size == 4 ? 0xFFFFFFFF :
                                                                 fd.size == 8 ? 0x00000000FFFFFFFF : ulong.MaxValue));
                    }
                    continue;
                }
                else
                {
                    if (pointer != 0)
                    {
                        effAddress = ReadPointer(pointer);
                    }

                    Write("({0:x16}) ", effAddress);
                    if (effAddress == 0)
                    {
                        WriteLine("");
                        continue;
                    }
                    if (fd.isString)
                    {
                        string str;

                        tp.GetString(effAddress, out str);
                        Write("{0}", str);
                    }
                    WriteLine("");
                }
            }

            /*
             * var fields =
             *  from f in obj.Fields
             *  orderby f.Offset
             *  select f;
             *
             * foreach (var field in fields)
             * {
             *  WriteLine("{0:x16} {1:x4} +{2:x4} {3,30} {4,30}", field.Type.Module.AssemblyId,
             *      field.Type.MetadataToken, field.Offset, TrimRight(field.Type.Name, 30), field.Name);
             *
             *
             * }
             * if (obj.StaticFields.Count > 0)
             * {
             *  var statFields =
             *      from s in obj.StaticFields
             *      orderby s.Offset
             *      select s;
             *  WriteLine("Static Fields:");
             *  foreach (var field in statFields)
             *  {
             *      WriteLine("{0:x16} {1:x4} +{2:x4} {3,30} {4,30}", field.Type.Module.AssemblyId,
             *          field.Type.MetadataToken, field.Offset, TrimRight(field.Type.Name, 30), field.Name);
             *  }
             * }
             * if (obj.ThreadStaticFields.Count > 0)
             * {
             *  var threadFields =
             *      from t in obj.ThreadStaticFields
             *      orderby t.Offset
             *      select t;
             *  WriteLine("Thread Static Fields:");
             *  foreach (var field in threadFields)
             *  {
             *      WriteLine("{0:x16} {1:x4} +{2:x4} {3,30} {4,30}", field.Type.Module.AssemblyId,
             *          field.Type.MetadataToken, field.Offset, TrimRight(field.Type.Name, 30), field.Name);
             *  }
             *
             * }
             */
        }
        private void InspectProcess(int pId)
        {
            using (DataTarget target = DataTarget.AttachToProcess(pId, 10000))
            {
                ShowCLRRuntimeInformation(target);

                ClrRuntime runtime = target.ClrVersions.First().CreateRuntime();

                LoadThreads(runtime);

                Dictionary <string, TypeEntry>   types       = new Dictionary <string, TypeEntry>();
                Dictionary <string, StringInfor> stringCount = new Dictionary <string, StringInfor>();

                ClrHeap heap = runtime.Heap;

                var finalizerQueueObjects = runtime.EnumerateFinalizerQueueObjectAddresses().ToList();
                var pinnedObjects         = runtime.EnumerateHandles().Where(h => h.IsPinned).Select(h => h.Object).ToList();
                var blockingObjects       = heap.EnumerateBlockingObjects().Select(x => x.Object).ToList();
                //var blockingObjects = runtime.Threads.SelectMany(x => x.BlockingObjects).Select(x => x.Object).ToList();

                foreach (ulong obj in heap.EnumerateObjects())
                {
                    ClrType type = heap.GetObjectType(obj);
                    var     size = type.GetSize(obj);
                    var     gen  = heap.GetGeneration(obj);
                    var     isInFinalizerQueue = finalizerQueueObjects.Contains(obj);
                    var     isPinned           = pinnedObjects.Contains(obj);
                    var     isBlocking         = blockingObjects.Contains(obj);

                    if (types.ContainsKey(type.Name))
                    {
                        types[type.Name].Count++;
                        types[type.Name].MinSize              = Math.Min(types[type.Name].MinSize, size);
                        types[type.Name].MaxSize              = Math.Max(types[type.Name].MaxSize, size);
                        types[type.Name].TotalSize           += size;
                        types[type.Name].Generation0         += gen == 0 ? 1 : 0;
                        types[type.Name].Generation1         += gen == 1 ? 1 : 0;
                        types[type.Name].Generation2         += gen == 2 ? 1 : 0;
                        types[type.Name].FinalizerQueueCount += isInFinalizerQueue ? 1 : 0;
                        types[type.Name].PinnedCount         += isPinned ? 1 : 0;
                        types[type.Name].BlockingCount       += isBlocking ? 1 : 0;
                    }
                    else
                    {
                        types[type.Name] = new TypeEntry
                        {
                            Name                = type.Name,
                            Count               = 1,
                            MinSize             = size,
                            MaxSize             = size,
                            TotalSize           = size,
                            Generation0         = gen == 0 ? 1 : 0,
                            Generation1         = gen == 1 ? 1 : 0,
                            Generation2         = gen == 2 ? 1 : 0,
                            FinalizerQueueCount = isInFinalizerQueue ? 1 : 0,
                            PinnedCount         = isPinned ? 1 : 0,
                            BlockingCount       = isBlocking ? 1 : 0,
                        };
                    }

                    if (type.IsString)
                    {
                        var text = (string)type.GetValue(obj);

                        if (stringCount.ContainsKey(text))
                        {
                            stringCount[text].Count++;
                            stringCount[text].Generation0 += gen == 0 ? 1 : 0;
                            stringCount[text].Generation1 += gen == 1 ? 1 : 0;
                            stringCount[text].Generation2 += gen == 2 ? 1 : 0;
                        }
                        else
                        {
                            stringCount[text] = new StringInfor
                            {
                                Text        = text,
                                Count       = 1,
                                Generation0 = gen == 0 ? 1 : 0,
                                Generation1 = gen == 1 ? 1 : 0,
                                Generation2 = gen == 2 ? 1 : 0,
                            };
                        }
                    }
                }

                var sortOrder = heapObjectsGrid.SortOrder == SortOrder.Ascending ?
                                ListSortDirection.Ascending : ListSortDirection.Descending;
                var sortCol = heapObjectsGrid.SortedColumn;

                int rowcount = 0;
                heapObjectsGrid.Rows.Clear();
                foreach (var val in types.Where(x => x.Value.Count > 1))
                {
                    var             infor   = val.Value;
                    DataGridViewRow gridrow = new DataGridViewRow();
                    gridrow.DefaultCellStyle.SelectionBackColor = Color.Black;
                    if (rowcount % 2 > 0)
                    {
                        gridrow.DefaultCellStyle.BackColor = Color.AliceBlue;
                    }
                    rowcount++;

                    DataGridViewTextBoxCell name = new DataGridViewTextBoxCell();
                    name.Value = infor.Name;
                    gridrow.Cells.Add(name);

                    DataGridViewTextBoxCell count = new DataGridViewTextBoxCell();
                    count.Style.Alignment = DataGridViewContentAlignment.BottomRight;
                    count.Style.Format    = "n0";
                    count.Value           = infor.Count;
                    gridrow.Cells.Add(count);

                    DataGridViewTextBoxCell minSize = new DataGridViewTextBoxCell();
                    minSize.Style.Alignment = DataGridViewContentAlignment.BottomRight;
                    minSize.Style.Format    = "n0";
                    if (infor.MinSize >= 85000)
                    {
                        minSize.Style.ForeColor = Color.Orange;
                        minSize.ToolTipText     = "Large Object Heap";
                    }
                    minSize.Value = infor.MinSize;
                    gridrow.Cells.Add(minSize);

                    DataGridViewTextBoxCell maxSize = new DataGridViewTextBoxCell();
                    maxSize.Style.Alignment = DataGridViewContentAlignment.BottomRight;
                    maxSize.Style.Format    = "n0";
                    if (infor.MaxSize >= 85000)
                    {
                        maxSize.Style.ForeColor = Color.Orange;
                        maxSize.ToolTipText     = "Large Object Heap";
                    }
                    maxSize.Value = infor.MaxSize;
                    gridrow.Cells.Add(maxSize);

                    DataGridViewTextBoxCell totalSize = new DataGridViewTextBoxCell();
                    totalSize.Style.Alignment = DataGridViewContentAlignment.BottomRight;
                    totalSize.Style.Format    = "n0";
                    totalSize.Value           = infor.TotalSize;
                    gridrow.Cells.Add(totalSize);

                    DataGridViewTextBoxCell generation0 = new DataGridViewTextBoxCell();
                    generation0.Value           = infor.Generation0;
                    generation0.Style.Alignment = DataGridViewContentAlignment.BottomRight;
                    generation0.Style.Format    = "n0";
                    gridrow.Cells.Add(generation0);

                    DataGridViewTextBoxCell generation1 = new DataGridViewTextBoxCell();
                    generation1.Value           = infor.Generation1;
                    generation1.Style.Alignment = DataGridViewContentAlignment.BottomRight;
                    generation1.Style.Format    = "n0";
                    gridrow.Cells.Add(generation1);

                    DataGridViewTextBoxCell generation2 = new DataGridViewTextBoxCell();
                    generation2.Value           = infor.Generation2;
                    generation2.Style.Alignment = DataGridViewContentAlignment.BottomRight;
                    generation2.Style.Format    = "n0";
                    gridrow.Cells.Add(generation2);

                    DataGridViewTextBoxCell finalizerQueue = new DataGridViewTextBoxCell();
                    finalizerQueue.Value           = infor.FinalizerQueueCount;
                    finalizerQueue.Style.Alignment = DataGridViewContentAlignment.BottomRight;
                    finalizerQueue.Style.Format    = "n0";
                    gridrow.Cells.Add(finalizerQueue);

                    DataGridViewTextBoxCell pinned = new DataGridViewTextBoxCell();
                    pinned.Value           = infor.PinnedCount;
                    pinned.Style.Alignment = DataGridViewContentAlignment.BottomRight;
                    pinned.Style.Format    = "n0";
                    gridrow.Cells.Add(pinned);

                    DataGridViewTextBoxCell blocking = new DataGridViewTextBoxCell();
                    blocking.Value           = infor.BlockingCount;
                    blocking.Style.Alignment = DataGridViewContentAlignment.BottomRight;
                    blocking.Style.Format    = "n0";
                    gridrow.Cells.Add(blocking);

                    heapObjectsGrid.Rows.Add(gridrow);
                }

                heapObjectsGrid.Columns[1].HeaderCell.ToolTipText = $"Total: { types.Values.Sum(x => x.Count).ToString("N0")} objects";
                heapObjectsGrid.Columns[4].HeaderCell.ToolTipText = $"Total: {types.Values.Sum(x => (long)x.TotalSize).ToString("N0")} bytes";

                if (sortCol != null)
                {
                    heapObjectsGrid.Sort(sortCol, sortOrder);
                }

                // Strings Grid View:
                rowcount = 0;
                stringsGrid.Rows.Clear();
                foreach (var str in stringCount)
                {
                    DataGridViewRow gridrow = new DataGridViewRow();
                    gridrow.DefaultCellStyle.SelectionBackColor = Color.Black;
                    if (rowcount % 2 > 0)
                    {
                        gridrow.DefaultCellStyle.BackColor = Color.AliceBlue;
                    }
                    rowcount++;

                    DataGridViewTextBoxCell name = new DataGridViewTextBoxCell();
                    name.Value = str.Key;
                    gridrow.Cells.Add(name);

                    DataGridViewTextBoxCell length = new DataGridViewTextBoxCell();
                    length.Style.Alignment = DataGridViewContentAlignment.BottomRight;
                    length.Style.Format    = "n0";
                    length.Value           = str.Key.Length;
                    gridrow.Cells.Add(length);

                    DataGridViewTextBoxCell count = new DataGridViewTextBoxCell();
                    count.Style.Alignment = DataGridViewContentAlignment.BottomRight;
                    count.Style.Format    = "n0";
                    count.Value           = str.Value.Count;
                    gridrow.Cells.Add(count);

                    DataGridViewTextBoxCell generation0 = new DataGridViewTextBoxCell();
                    generation0.Value           = str.Value.Generation0;
                    generation0.Style.Alignment = DataGridViewContentAlignment.BottomRight;
                    generation0.Style.Format    = "n0";
                    gridrow.Cells.Add(generation0);

                    DataGridViewTextBoxCell generation1 = new DataGridViewTextBoxCell();
                    generation1.Value           = str.Value.Generation1;
                    generation1.Style.Alignment = DataGridViewContentAlignment.BottomRight;
                    generation1.Style.Format    = "n0";
                    gridrow.Cells.Add(generation1);

                    DataGridViewTextBoxCell generation2 = new DataGridViewTextBoxCell();
                    generation2.Value           = str.Value.Generation2;
                    generation2.Style.Alignment = DataGridViewContentAlignment.BottomRight;
                    generation2.Style.Format    = "n0";
                    gridrow.Cells.Add(generation2);

                    stringsGrid.Rows.Add(gridrow);
                }
            }
        }
Beispiel #19
0
        /// <summary>
        /// Find all Strings in Heap an generate a dublicate string report
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonStrings_Click(object sender, EventArgs e)
        {
            if (Process == null)
            {
                return;
            }

            saveFileDialogStrings.FileName = String.Format("clrmd_{0:yyyyMMdd_HHmmss}", DateTime.Now);
            if (saveFileDialogStrings.ShowDialog() != DialogResult.OK)
            {
                return;
            }

            if (File.Exists(saveFileDialogStrings.FileName))
            {
                File.Delete(saveFileDialogStrings.FileName);
            }

            Cursor.Current = Cursors.WaitCursor;

            HashSet <StringObjectHelper> stringObjectList = new HashSet <StringObjectHelper>();
            ulong fullSize    = 0;
            int   objectCount = 0;

            using (StreamWriter writer = new StreamWriter(saveFileDialogStrings.FileName, true, Encoding.UTF8))
            {
                using (DataTarget dataTarget = DataTarget.AttachToProcess(Process.Id, dataTargetTimeOut, dataTargetAttachFlag))
                {
                    ClrInfo    clrVersion = dataTarget.ClrVersions.First();
                    ClrRuntime runtime    = clrVersion.CreateRuntime();
                    if (runtime.Heap.CanWalkHeap)
                    {
                        foreach (ulong ptr in runtime.Heap.EnumerateObjectAddresses())
                        {
                            ClrType type = runtime.Heap.GetObjectType(ptr);

                            if (type == null || type.IsString == false)
                            {
                                continue;
                            }

                            StringObjectHelper stringObject = new StringObjectHelper();
                            stringObject.String = (string)type.GetValue(ptr);
                            stringObject.Size   = type.GetSize(ptr);

                            StringObjectHelper stringObjectFound;
                            if (stringObjectList.TryGetValue(stringObject, out stringObjectFound))
                            {
                                stringObjectFound.PtrList.Add(ptr);
                            }
                            else
                            {
                                stringObject.PtrList.Add(ptr);
                                stringObjectList.Add(stringObject);
                            }
                            objectCount++;
                            fullSize += stringObject.Size;

                            //write all strings
                            writer.WriteLine("**{0}#{1:X}#G{2}#{3:n0}",
                                             objectCount,
                                             ptr,
                                             type.Heap.GetGeneration(ptr),
                                             stringObject.Size);

                            writer.WriteLine(stringObject.String);
                        }
                    }

                    writer.WriteLine();
                    writer.WriteLine("**Position#HeapPtr#Generation#Size");
                    writer.WriteLine();
                    writer.WriteLine("{0:n0} String Objects", objectCount);
                    writer.WriteLine("{0:n0} String unique Strings", stringObjectList.Count);
                    writer.WriteLine("{0:n0} Bytes", fullSize);
                }
            }

            //write dublicate info
            var orderedList = stringObjectList.OrderByDescending(x => x.PtrList.Count);

            using (StreamWriter writer = new StreamWriter(saveFileDialogStrings.FileName + ".unique.csv", true, Encoding.UTF8))
            {
                writer.WriteLine("Count;Size;FullSize;Content;Ptrs");
                foreach (StringObjectHelper so in orderedList)
                {
                    string pointerList = String.Join(",", so.PtrList.Select(x => String.Format("x{0:X}", x)));
                    writer.WriteLine(String.Format("{0};{1};{2};{3};{4}",
                                                   so.PtrList.Count,
                                                   so.Size,
                                                   so.Size * (ulong)so.PtrList.Count,
                                                   (so.String.Length > 50 ? so.String.Substring(0, 50) + " ..." : so.String).Replace("'", "").Replace(";", "").Replace("\r", " ").Replace("\n", ""),
                                                   pointerList.Length > 50 ? pointerList.Substring(0, 50) + " ..." : pointerList));
                }
            }

            Cursor.Current = Cursors.Default;
        }
Beispiel #20
0
 /// <summary>
 ///     Returns the simple value of an instance of this type.  Undefined behavior if HasSimpleValue returns false.
 ///     For example ELEMENT_TYPE_I4 is an "int" and the return value of this function would be an int.
 /// </summary>
 /// <param name="address">The address of an instance of this type.</param>
 /// <returns>System.Object.</returns>
 public object GetValue(ulong address) => ClrType.GetValue(address);