Beispiel #1
0
        private bool FillGCDesc()
        {
            NativeRuntime runtime = _heap.NativeRuntime;

            int entries;

            if (!runtime.MemoryReader.TryReadDword(_eeType - (ulong)IntPtr.Size, out entries))
            {
                return(false);
            }

            // Get entries in map
            if (entries < 0)
            {
                entries = -entries;
            }

            int read;
            int slots = 1 + entries * 2;

            byte[] buffer = new byte[slots * IntPtr.Size];
            if (!runtime.ReadMemory(_eeType - (ulong)(slots * IntPtr.Size), buffer, buffer.Length, out read) || read != buffer.Length)
            {
                return(false);
            }

            // Construct the gc desc
            _gcDesc = new GCDesc(buffer);
            return(true);
        }
Beispiel #2
0
        public override IEnumerable <ClrReference> EnumerateReferencesWithFields(ulong obj, ClrType type, bool carefully, bool considerDependantHandles)
        {
            if (type is null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            if (considerDependantHandles)
            {
                ImmutableArray <(ulong Source, ulong Target)> dependent = GetHeapData().GetDependentHandles(_helpers);

                if (dependent.Length > 0)
                {
                    int index = dependent.Search(obj, (x, y) => x.Source.CompareTo(y));
                    if (index != -1)
                    {
                        while (index >= 1 && dependent[index - 1].Source == obj)
                        {
                            index--;
                        }

                        while (index < dependent.Length && dependent[index].Source == obj)
                        {
                            ulong     dependantObj = dependent[index++].Target;
                            ClrObject target       = new ClrObject(dependantObj, GetObjectType(dependantObj));
                            yield return(ClrReference.CreateFromDependentHandle(target));
                        }
                    }
                }
            }

            if (type.ContainsPointers)
            {
                GCDesc gcdesc = type.GCDesc;
                if (!gcdesc.IsEmpty)
                {
                    ulong size = GetObjectSize(obj, type);
                    if (carefully)
                    {
                        ClrSegment?seg = GetSegmentByAddress(obj);
                        if (seg is null || obj + size > seg.End || (!seg.IsLargeObjectSegment && size > MaxGen2ObjectSize))
                        {
                            yield break;
                        }
                    }

                    foreach ((ulong reference, int offset) in gcdesc.WalkObject(obj, size, _helpers.DataReader))
                    {
                        ClrObject target = new ClrObject(reference, GetObjectType(reference));
                        yield return(ClrReference.CreateFromFieldOrArray(target, type, offset));
                    }
                }
            }
        }
Beispiel #3
0
        private bool FillGCDesc()
        {
            DesktopRuntimeBase runtime = DesktopHeap.DesktopRuntime;

            int entries;
            if (!runtime.ReadDword(_constructedMT - (ulong)IntPtr.Size, out entries))
                return false;

            // Get entries in map
            if (entries < 0)
                entries = -entries;

            int read;
            int slots = 1 + entries * 2;
            byte[] buffer = new byte[slots * IntPtr.Size];
            if (!runtime.ReadMemory(_constructedMT - (ulong)(slots * IntPtr.Size), buffer, buffer.Length, out read) || read != buffer.Length)
                return false;

            // Construct the gc desc
            _gcDesc = new GCDesc(buffer);
            return true;
        }
Beispiel #4
0
        private bool FillGCDesc()
        {
            NativeRuntime runtime = _heap.NativeRuntime;

            int entries;
            if (!runtime.MemoryReader.TryReadDword(_eeType - (ulong)IntPtr.Size, out entries))
                return false;

            // Get entries in map
            if (entries < 0)
                entries = -entries;

            int read;
            int slots = 1 + entries * 2;
            byte[] buffer = new byte[slots * IntPtr.Size];
            if (!runtime.ReadMemory(_eeType - (ulong)(slots * IntPtr.Size), buffer, buffer.Length, out read) || read != buffer.Length)
                return false;

            // Construct the gc desc
            _gcDesc = new GCDesc(buffer);
            return true;
        }
Beispiel #5
0
        private static object DeserializeInner(RuntimeTypeHandle[] runtimeTypeHandles, byte *buffer, long length)
        {
            byte *objectId = buffer + IntPtr.Size;

            while (objectId < buffer + length)
            {
                IntPtr typeHandle = IntPtr.Size == 8 ? runtimeTypeHandles[(int)*(long *)objectId].Value : runtimeTypeHandles[*(int *)objectId].Value;
                bool   isArray    = ((long)typeHandle & 0x2) == 0x2;

                var mt = (MethodTable *)typeHandle;
                if (isArray)
                {
                    mt = IntPtr.Size == 8 ? (MethodTable *)*(long *)(typeHandle + 6) : (MethodTable *)*(int *)(typeHandle + 6); // TODO: Is this correct for 32-bit?
                }

                long objectSize       = mt->BaseSize;
                var  flags            = mt->Flags;
                bool hasComponentSize = (flags & 0x80000000) == 0x80000000;

                if (hasComponentSize)
                {
                    var numComponents = (long)*(int *)(objectId + IntPtr.Size);
                    objectSize += numComponents * mt->ComponentSize;
                }

                bool containsPointerOrCollectible = (flags & 0x10000000) == 0x10000000 || (flags & 0x1000000) == 0x1000000;
                if (containsPointerOrCollectible)
                {
                    var entries = *(int *)((byte *)mt - IntPtr.Size);
                    if (entries < 0)
                    {
                        entries -= entries;
                    }

                    var slots = 1 + entries * 2;

                    var gcdesc = new GCDesc(buffer, (byte *)mt - (slots * IntPtr.Size), slots * IntPtr.Size);

                    if (IntPtr.Size == 8)
                    {
                        gcdesc.FixupObject64(objectId, objectSize);
                    }
                    else
                    {
                        gcdesc.FixupObject32(objectId, objectSize);
                    }
                }

                if (IntPtr.Size == 8)
                {
                    *(long *)objectId = (long)mt;
                }
                else
                {
                    *(int *)objectId = (int)mt;
                }

                objectId += objectSize + Padding(objectSize, IntPtr.Size);
            }

            var tmp = buffer + IntPtr.Size;

            return(Unsafe.Read <object>(&tmp));
        }
Beispiel #6
0
        public override IEnumerable <ClrObject> EnumerateObjectReferences(ulong obj, ClrType type, bool carefully, bool considerDependantHandles)
        {
            if (type is null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            if (considerDependantHandles)
            {
                ImmutableArray <(ulong Source, ulong Target)> dependent = GetHeapData().GetDependentHandles(_helpers);

                if (dependent.Length > 0)
                {
                    int index = dependent.Search(obj, (x, y) => x.Source.CompareTo(y));
                    if (index != -1)
                    {
                        while (index >= 1 && dependent[index - 1].Source == obj)
                        {
                            index--;
                        }

                        while (index < dependent.Length && dependent[index].Source == obj)
                        {
                            ulong dependantObj = dependent[index++].Target;
                            yield return(new ClrObject(dependantObj, GetObjectType(dependantObj)));
                        }
                    }
                }
            }

            if (type.IsCollectible)
            {
                ulong la = _helpers.DataReader.ReadPointer(type.LoaderAllocatorHandle);
                if (la != 0)
                {
                    yield return(new ClrObject(la, GetObjectType(la)));
                }
            }

            if (type.ContainsPointers)
            {
                GCDesc gcdesc = type.GCDesc;
                if (!gcdesc.IsEmpty)
                {
                    ulong size = GetObjectSize(obj, type);
                    if (carefully)
                    {
                        ClrSegment?seg = GetSegmentByAddress(obj);
                        if (seg is null || obj + size > seg.End || (!seg.IsLargeObjectSegment && size > MaxGen2ObjectSize))
                        {
                            yield break;
                        }
                    }

                    int    intSize = (int)size;
                    byte[] buffer  = ArrayPool <byte> .Shared.Rent(intSize);

                    try
                    {
                        int read = _helpers.DataReader.Read(obj, new Span <byte>(buffer, 0, intSize));
                        if (read > IntPtr.Size)
                        {
                            foreach ((ulong reference, int offset) in gcdesc.WalkObject(buffer, read))
                            {
                                yield return(new ClrObject(reference, GetObjectType(reference)));
                            }
                        }
                    }
                    finally
                    {
                        ArrayPool <byte> .Shared.Return(buffer);
                    }
                }
            }
        }
Beispiel #7
0
        private static unsafe void WriteObjectGraphToDisk(byte *stackAllocatedData, Stream stream, Dictionary <object, long> serializedObjectMap, Queue <object> objectQueue, RuntimeTypeHandleDictionary mtTokenMap, ref long lastReservedObjectEnd)
        {
            long nextObjectHeaderFilePointer = 0;

            while (objectQueue.Count != 0)
            {
                object       o        = objectQueue.Dequeue();
                ref TypeInfo typeInfo = ref mtTokenMap.GetOrAddValueRef(Type.GetTypeHandle(o));

                long mtToken;

                if (typeInfo != null)
                {
                    mtToken = typeInfo.MTToken;
                }
                else
                {
                    mtToken  = mtTokenMap.Count - 1;
                    typeInfo = GetObjectInfo(o, mtToken);
                }

                long hashCode = (RuntimeHelpers.GetHashCode(o) & 0x0fffffff) | (1 << 27) | (1 << 26);

                fixed(byte *data = &GetRawData(o))
                {
                    MethodTable *mt;

                    if (IntPtr.Size == 8)
                    {
                        *(long *)stackAllocatedData       = hashCode;
                        *(long *)(stackAllocatedData + 8) = mtToken;
                        stream.Write(new ReadOnlySpan <byte>(stackAllocatedData, 16));
                        mt = (MethodTable *)*(long *)(data - IntPtr.Size);
                    }
                    else
                    {
                        *(int *)stackAllocatedData       = (int)hashCode;
                        *(int *)(stackAllocatedData + 4) = (int)mtToken;
                        stream.Write(new ReadOnlySpan <byte>(stackAllocatedData, 8));
                        mt = (MethodTable *)*(int *)(data - IntPtr.Size);
                    }

                    uint flags            = mt->Flags;
                    bool hasComponentSize = (flags & 0x80000000) == 0x80000000;

                    long objectSize = mt->BaseSize;

                    if (hasComponentSize)
                    {
                        var numComponents = (long)*(int *)data;
                        objectSize += numComponents * mt->ComponentSize;
                    }

                    var remainingSize = objectSize - IntPtr.Size - IntPtr.Size; // because we have already written the object header and MT Token

                    if (remainingSize <= int.MaxValue)
                    {
                        stream.Write(new ReadOnlySpan <byte>(data, (int)remainingSize));
                    }
                    else
                    {
                        WriteLargeObject(stream, data, remainingSize);
                    }

                    bool containsPointersOrCollectible = (flags & 0x10000000) == 0x10000000 || (flags & 0x1000000) == 0x1000000;

                    if (containsPointersOrCollectible)
                    {
                        var gcdesc = new GCDesc(typeInfo.GCDescData, typeInfo.GCDescSize);
                        gcdesc.EnumerateObject(data, objectSize, serializedObjectMap, objectQueue, stream, nextObjectHeaderFilePointer, ref lastReservedObjectEnd);
                    }

                    nextObjectHeaderFilePointer += objectSize + Padding(objectSize, IntPtr.Size);
                    stream.Seek(nextObjectHeaderFilePointer, SeekOrigin.Begin);
                }
            }